mirror of
https://gitlab.com/crafty-controller/crafty-4.git
synced 2024-08-30 18:23:09 +00:00
Merge branch 'dev' into feature/steamcmd
This commit is contained in:
commit
7c2ce9dcc5
@ -3,6 +3,7 @@ docker/
|
||||
.dockerignore
|
||||
Dockerfile
|
||||
docker-compose.yml
|
||||
docker-compose.yml.example
|
||||
|
||||
# git & gitlab related
|
||||
.git/
|
||||
@ -17,6 +18,8 @@ docker-compose.yml
|
||||
.venv
|
||||
.vscode
|
||||
crafty_commander.exe
|
||||
CHANGELOG.md
|
||||
CONTRIBUTING.md
|
||||
DBCHANGES.md
|
||||
docker-compose.yml.example
|
||||
README.md
|
||||
sonar-project.properties
|
||||
|
@ -28,7 +28,7 @@ docker-build-dev:
|
||||
docker version
|
||||
- docker run --rm --privileged aptman/qus -- -r
|
||||
- docker run --rm --privileged aptman/qus -s -- -p aarch64 x86_64
|
||||
- echo $CI_BUILD_TOKEN | docker login -u "$CI_REGISTRY_USER" --password-stdin $CI_REGISTRY
|
||||
- echo $CI_JOB_TOKEN | docker login -u "$CI_REGISTRY_USER" --password-stdin $CI_REGISTRY
|
||||
- echo $DOCKERHUB_TOKEN | docker login -u "$DOCKERHUB_USER" --password-stdin $DOCKERHUB_REGISTRY
|
||||
script:
|
||||
- |
|
||||
@ -45,6 +45,7 @@ docker-build-dev:
|
||||
--build-arg "BUILD_DATE=$(date +"%Y-%m-%dT%H:%M:%SZ")"
|
||||
--build-arg "BUILD_REF=${CI_COMMIT_SHA}"
|
||||
--build-arg "CRAFTY_VER=${VERSION}"
|
||||
--provenance false
|
||||
--tag "$CI_REGISTRY_IMAGE${tag}"
|
||||
--tag "arcadiatechnology/crafty-4${tag}"
|
||||
--platform linux/arm64/v8,linux/amd64
|
||||
@ -84,7 +85,7 @@ docker-build-prod:
|
||||
docker version
|
||||
- docker run --rm --privileged aptman/qus -- -r
|
||||
- docker run --rm --privileged aptman/qus -s -- -p aarch64 x86_64
|
||||
- echo $CI_BUILD_TOKEN | docker login -u "$CI_REGISTRY_USER" --password-stdin $CI_REGISTRY
|
||||
- echo $CI_JOB_TOKEN | docker login -u "$CI_REGISTRY_USER" --password-stdin $CI_REGISTRY
|
||||
- echo $DOCKERHUB_TOKEN | docker login -u "$DOCKERHUB_USER" --password-stdin $DOCKERHUB_REGISTRY
|
||||
script:
|
||||
- |
|
||||
@ -100,6 +101,7 @@ docker-build-prod:
|
||||
--build-arg "BUILD_DATE=$(date +"%Y-%m-%dT%H:%M:%SZ")"
|
||||
--build-arg "BUILD_REF=${CI_COMMIT_SHA}"
|
||||
--build-arg "CRAFTY_VER=${VERSION}"
|
||||
--provenance false
|
||||
--tag "$CI_REGISTRY_IMAGE:$VERSION"
|
||||
--tag "$CI_REGISTRY_IMAGE:latest"
|
||||
--tag "arcadiatechnology/crafty-4:$VERSION"
|
||||
|
@ -57,3 +57,27 @@ pylint:
|
||||
reports:
|
||||
codequality: codeclimate.json
|
||||
when: always
|
||||
|
||||
# SonarQube/SonarCloud - Code Climate & QA [https://www.sonarsource.com]
|
||||
sonarcloud-check:
|
||||
stage: lint
|
||||
image:
|
||||
name: sonarsource/sonar-scanner-cli:latest
|
||||
entrypoint: [""]
|
||||
tags:
|
||||
- docker
|
||||
rules:
|
||||
- if: "$SONAR_TOKEN == null"
|
||||
when: never
|
||||
- if: "$CODE_QUALITY_DISABLED"
|
||||
when: never
|
||||
- if: "$CI_COMMIT_TAG || $CI_COMMIT_BRANCH"
|
||||
variables:
|
||||
SONAR_USER_HOME: "${CI_PROJECT_DIR}/.sonar" # Defines the location of the analysis task cache
|
||||
GIT_DEPTH: "0" # Tells git to fetch all the branches of the project, required by the analysis task
|
||||
cache:
|
||||
key: "${CI_JOB_NAME}"
|
||||
paths:
|
||||
- .sonar/cache
|
||||
script:
|
||||
- sonar-scanner
|
||||
|
@ -606,5 +606,5 @@ preferred-modules=
|
||||
|
||||
# Exceptions that will emit a warning when being caught. Defaults to
|
||||
# "BaseException, Exception".
|
||||
overgeneral-exceptions=BaseException,
|
||||
Exception
|
||||
overgeneral-exceptions=builtins.BaseException,
|
||||
builtins.Exception
|
||||
|
60
CHANGELOG.md
60
CHANGELOG.md
@ -1,5 +1,5 @@
|
||||
# Changelog
|
||||
## --- [4.0.23] - 2023/TBD
|
||||
## --- [4.1.4] - 2023/TBD
|
||||
### New features
|
||||
TBD
|
||||
### Bug fixes
|
||||
@ -10,6 +10,64 @@ TBD
|
||||
TBD
|
||||
<br><br>
|
||||
|
||||
## --- [4.1.3] - 2023/07/18
|
||||
### Bug fixes
|
||||
- Include tzdata in Docker image ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/604))
|
||||
- Fix text/formatting issue on server config page ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/602))
|
||||
- Bump required version of PyYAML to 6.0.1 ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/609))
|
||||
- Fix enable/disable schedule toggles on schedule list ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/606))
|
||||
- Fix formatting on Creation page when server jars is unavailable ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/601))
|
||||
### Refactor
|
||||
- Replace "in_file" helper method ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/605))
|
||||
### Tweaks
|
||||
- Add public status link to login ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/608))
|
||||
<br><br>
|
||||
|
||||
## --- [4.1.2] - 2023/06/18
|
||||
### Bug fixes
|
||||
- Fix upload root files being hidden ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/590))
|
||||
- Send empty json for no banned/cached players ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/589))
|
||||
- Bump Tornado from 6.0 to 6.3.2 in response to CVE-2023-28370 ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/591))
|
||||
- Fix bug where commands would show "command_server" when initially created ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/592))
|
||||
- Add ID autofield to management CraftySettings class ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/599))
|
||||
### Refactor
|
||||
- Optimize player management page ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/593))
|
||||
### Tweaks
|
||||
- Remove bedrock servers in serverjars options ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/595))
|
||||
- Bump cryptography & pyOpenSSL ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/596))
|
||||
- Bump requests ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/600))
|
||||
### Lang
|
||||
- Update es_ES & pl_PL lang, thank you `.lucyy_` & `terrariadlc` ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/597))
|
||||
<br><br>
|
||||
|
||||
## --- [4.1.1] - 2023/05/23
|
||||
### Bug fixes
|
||||
- Fix task scheduling where a command was not sent to the DB ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/586))
|
||||
### Tweaks
|
||||
- Improve the UI on several areas of the Crafty Panel ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/547))
|
||||
- Improve creation page errors / Server Jars Credit ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/587))
|
||||
<br><br>
|
||||
|
||||
## --- [4.1.0] - 2023/05/15
|
||||
### New features
|
||||
- Mobile PWA App (beta) | Ability to add a Crafty icon to your mobile's home screen ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/576))
|
||||
- [New Crafty Documentation release](https://docs.craftycontrol.com)
|
||||
### Refactor
|
||||
- Frontend Ajax Refactor | Start using API to send Remote Comms to Server ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/565))
|
||||
- MKDocs Release | Replace wiki names with docs ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/583))
|
||||
### Bug fixes
|
||||
- Fix pipelines failing to build from gitlab pre-defined variable deprecation ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/582))
|
||||
- Fix incompatible buildx provenance meta, causing digest issues on GL/DH container registries ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/582))
|
||||
- Fix Auth'd servers in roles | Refine server ordering ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/574))
|
||||
- Fix import loop detection ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/575))
|
||||
- Fix Cargo errors on Ubuntu 23.04 installs ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/579))
|
||||
- Fix project root error on first start ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/580))
|
||||
### Tweaks
|
||||
- Check for python version so we don't just fail out on unsupported python versions ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/577))
|
||||
- Show warning for serverjars API connection issues ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/581))
|
||||
- Retain pathing in execution command on backup restore ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/578))
|
||||
<br><br>
|
||||
|
||||
## --- [4.0.22] - 2023/04/08
|
||||
### Bug fixes
|
||||
- Fix dashboard crash for users without disks or if crafty doesn't have permission to access mount point ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/571))
|
||||
|
@ -26,6 +26,7 @@ RUN apt-get update \
|
||||
openjdk-11-jre-headless \
|
||||
openjdk-17-jre-headless \
|
||||
lib32stdc++6 \
|
||||
tzdata \
|
||||
&& apt-get autoremove \
|
||||
&& apt-get clean
|
||||
|
||||
@ -68,7 +69,7 @@ LABEL \
|
||||
org.opencontainers.image.title="Crafty Controller" \
|
||||
org.opencontainers.image.description="A Game Server Control Panel / Launcher" \
|
||||
org.opencontainers.image.url="https://craftycontrol.com/" \
|
||||
org.opencontainers.image.documentation="https://wiki.craftycontrol.com/" \
|
||||
org.opencontainers.image.documentation="https://docs.craftycontrol.com" \
|
||||
org.opencontainers.image.source="https://gitlab.com/crafty-controller/crafty-4" \
|
||||
org.opencontainers.image.vendor="Arcadia Technology, LLC." \
|
||||
org.opencontainers.image.licenses="GPL-3.0"
|
||||
|
@ -1,5 +1,5 @@
|
||||
[![Crafty Logo](app/frontend/static/assets/images/logo_long.svg)](https://craftycontrol.com)
|
||||
# Crafty Controller 4.0.23
|
||||
# Crafty Controller 4.1.4
|
||||
> Python based Control Panel for your Minecraft Server
|
||||
|
||||
## What is Crafty Controller?
|
||||
@ -9,7 +9,7 @@ a web interface for the server administrators to interact with their servers. Cr
|
||||
is compatible with Docker, Linux, Windows 7, Windows 8 and Windows 10.
|
||||
|
||||
## Documentation
|
||||
Documentation available on [wiki.craftycontrol.com](https://craftycontrol.com)
|
||||
Documentation available on [Crafty Docs](https://docs.craftycontrol.com)
|
||||
|
||||
## Meta
|
||||
Project Homepage - https://craftycontrol.com
|
||||
|
@ -255,6 +255,7 @@ class ServersController(metaclass=Singleton):
|
||||
|
||||
@staticmethod
|
||||
def get_authorized_servers(user_id):
|
||||
server_ids = []
|
||||
server_data: t.List[t.Dict[str, t.Any]] = []
|
||||
user_roles = HelperUsers.user_role_query(user_id)
|
||||
for user in user_roles:
|
||||
@ -262,6 +263,8 @@ class ServersController(metaclass=Singleton):
|
||||
user.role_id
|
||||
)
|
||||
for role in role_servers:
|
||||
if role.server_id.server_id not in server_ids:
|
||||
server_ids.append(role.server_id.server_id)
|
||||
server_data.append(
|
||||
ServersController().get_server_instance_by_id(
|
||||
role.server_id.server_id
|
||||
@ -277,11 +280,10 @@ class ServersController(metaclass=Singleton):
|
||||
for role in roles_list:
|
||||
role_users = HelperUsers.get_users_from_role(role.role_id)
|
||||
for user_role in role_users:
|
||||
user_ids.add(user_role.user_id)
|
||||
user_ids.add(user_role.user_id.user_id)
|
||||
|
||||
for user_id in HelperUsers.get_super_user_list():
|
||||
user_ids.add(user_id)
|
||||
|
||||
return user_ids
|
||||
|
||||
def get_all_servers_stats(self):
|
||||
@ -515,6 +517,25 @@ class ServersController(metaclass=Singleton):
|
||||
# **********************************************************************************
|
||||
# Servers Helpers Methods
|
||||
# **********************************************************************************
|
||||
@staticmethod
|
||||
def get_cached_players(server_id):
|
||||
srv = ServersController().get_server_instance_by_id(server_id)
|
||||
stats = srv.stats_helper.get_server_stats()
|
||||
server_path = stats["server_id"]["path"]
|
||||
path = os.path.join(server_path, "usercache.json")
|
||||
|
||||
try:
|
||||
with open(
|
||||
Helpers.get_os_understandable_path(path), encoding="utf-8"
|
||||
) as file:
|
||||
content = file.read()
|
||||
file.close()
|
||||
except Exception as ex:
|
||||
logger.error(ex)
|
||||
return {}
|
||||
|
||||
return json.loads(content)
|
||||
|
||||
@staticmethod
|
||||
def get_banned_players(server_id):
|
||||
srv = ServersController().get_server_instance_by_id(server_id)
|
||||
@ -529,8 +550,8 @@ class ServersController(metaclass=Singleton):
|
||||
content = file.read()
|
||||
file.close()
|
||||
except Exception as ex:
|
||||
print(ex)
|
||||
return None
|
||||
logger.error(ex)
|
||||
return {}
|
||||
|
||||
return json.loads(content)
|
||||
|
||||
|
@ -89,6 +89,7 @@ class UsersController:
|
||||
},
|
||||
},
|
||||
"hints": {"type": "boolean"},
|
||||
"server_order": {"type": "string"},
|
||||
}
|
||||
|
||||
# **********************************************************************************
|
||||
|
@ -153,6 +153,9 @@ class ServerJars:
|
||||
def _get_server_type_list(self):
|
||||
url = "/api/fetchTypes/"
|
||||
response = self._get_api_result(url)
|
||||
if "bedrock" in response.keys():
|
||||
# remove pocketmine from options
|
||||
del response["bedrock"]
|
||||
return response
|
||||
|
||||
def download_jar(self, jar, server, version, path, server_id):
|
||||
|
@ -43,6 +43,7 @@ class AuditLog(BaseModel):
|
||||
# Crafty Settings Class
|
||||
# **********************************************************************************
|
||||
class CraftySettings(BaseModel):
|
||||
id = AutoField()
|
||||
secret_api_key = CharField(default="")
|
||||
cookie_secret = CharField(default="")
|
||||
login_photo = CharField(default="login_1.jpg")
|
||||
|
@ -386,7 +386,7 @@ class HelperUsers:
|
||||
|
||||
@staticmethod
|
||||
def get_users_from_role(role_id):
|
||||
UserRoles.select().where(UserRoles.role_id == role_id).execute()
|
||||
return UserRoles.select().where(UserRoles.role_id == role_id).execute()
|
||||
|
||||
# **********************************************************************************
|
||||
# ApiKeys Methods
|
||||
|
@ -16,6 +16,7 @@ import zipfile
|
||||
import pathlib
|
||||
import ctypes
|
||||
import shutil
|
||||
import shlex
|
||||
import subprocess
|
||||
import itertools
|
||||
from datetime import datetime
|
||||
@ -148,6 +149,29 @@ class Helpers:
|
||||
logger.error(f"Unable to resolve remote bedrock download url! \n{e}")
|
||||
return False
|
||||
|
||||
def get_execution_java(self, value, execution_command):
|
||||
if self.is_os_windows():
|
||||
execution_list = shlex.split(execution_command, posix=False)
|
||||
else:
|
||||
execution_list = shlex.split(execution_command, posix=True)
|
||||
if (
|
||||
not any(value in path for path in self.find_java_installs())
|
||||
and value != "java"
|
||||
):
|
||||
return
|
||||
if value != "java":
|
||||
if self.is_os_windows():
|
||||
execution_list[0] = '"' + value + '/bin/java"'
|
||||
else:
|
||||
execution_list[0] = '"' + value + '"'
|
||||
else:
|
||||
execution_list[0] = "java"
|
||||
execution_command = ""
|
||||
for item in execution_list:
|
||||
execution_command += item + " "
|
||||
|
||||
return execution_command
|
||||
|
||||
def detect_java(self):
|
||||
if len(self.find_java_installs()) > 0:
|
||||
return True
|
||||
@ -302,6 +326,16 @@ class Helpers:
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def check_address_status(address):
|
||||
try:
|
||||
response = requests.get(address, timeout=2)
|
||||
return (
|
||||
response.status_code // 100 == 2
|
||||
) # Check if the status code starts with 2
|
||||
except requests.RequestException:
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def check_port(server_port):
|
||||
try:
|
||||
@ -474,9 +508,9 @@ class Helpers:
|
||||
|
||||
return mounts
|
||||
|
||||
def is_subdir(self, server_path, root_dir):
|
||||
server_path = os.path.realpath(server_path)
|
||||
root_dir = os.path.realpath(root_dir)
|
||||
def is_subdir(self, child_path, parent_path):
|
||||
server_path = os.path.realpath(child_path)
|
||||
root_dir = os.path.realpath(parent_path)
|
||||
|
||||
if self.is_os_windows():
|
||||
try:
|
||||
@ -1211,22 +1245,6 @@ class Helpers:
|
||||
return temp_dir
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def in_path(parent_path, child_path):
|
||||
# Smooth out relative path names, note: if you are concerned about
|
||||
# symbolic links, you should use os.path.realpath too
|
||||
parent_path = os.path.abspath(parent_path)
|
||||
child_path = os.path.abspath(child_path)
|
||||
|
||||
# Compare the common path of the parent and child path with the
|
||||
# common path of just the parent path. Using the commonpath method
|
||||
# on just the parent path will regularise the path name in the same way
|
||||
# as the comparison that deals with both paths, removing any trailing
|
||||
# path separator
|
||||
return os.path.commonpath([parent_path]) == os.path.commonpath(
|
||||
[parent_path, child_path]
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def download_file(executable_url, jar_path):
|
||||
try:
|
||||
@ -1261,3 +1279,24 @@ class Helpers:
|
||||
if region == "EN":
|
||||
return "en"
|
||||
return lang + "-" + region
|
||||
|
||||
@staticmethod
|
||||
def get_player_avatar(uuid_player):
|
||||
mojang_response = requests.get(
|
||||
f"https://sessionserver.mojang.com/session/minecraft/profile/{uuid_player}",
|
||||
timeout=10,
|
||||
)
|
||||
if mojang_response.status_code == 200:
|
||||
uuid_profile = mojang_response.json()
|
||||
profile_properties = uuid_profile["properties"]
|
||||
for prop in profile_properties:
|
||||
if prop["name"] == "textures":
|
||||
decoded_bytes = base64.b64decode(prop["value"])
|
||||
decoded_str = decoded_bytes.decode("utf-8")
|
||||
texture_json = json.loads(decoded_str)
|
||||
skin_url = texture_json["textures"]["SKIN"]["url"]
|
||||
skin_response = requests.get(skin_url, stream=True, timeout=10)
|
||||
if skin_response.status_code == 200:
|
||||
return base64.b64encode(skin_response.content)
|
||||
else:
|
||||
return
|
||||
|
@ -11,6 +11,7 @@ import subprocess
|
||||
import html
|
||||
import urllib.request
|
||||
import glob
|
||||
import json
|
||||
|
||||
from zoneinfo import ZoneInfo
|
||||
|
||||
@ -132,6 +133,15 @@ class ServerInstance:
|
||||
self.server_object = HelperServers.get_server_obj(self.server_id)
|
||||
self.stats_helper = HelperServerStats(self.server_id)
|
||||
self.last_backup_failed = False
|
||||
try:
|
||||
with open(
|
||||
os.path.join(self.server_object.path, "db_stats", "players_cache.json"),
|
||||
"r",
|
||||
encoding="utf-8",
|
||||
) as f:
|
||||
self.player_cache = list(json.load(f).values())
|
||||
except:
|
||||
self.player_cache = []
|
||||
try:
|
||||
self.tz = get_localzone()
|
||||
except ZoneInfoNotFoundError as e:
|
||||
@ -799,6 +809,7 @@ class ServerInstance:
|
||||
)
|
||||
if self.settings["stop_command"]:
|
||||
self.send_command(self.settings["stop_command"])
|
||||
self.write_player_cache()
|
||||
else:
|
||||
# windows will need to be handled separately for Ctrl+C
|
||||
self.process.terminate()
|
||||
@ -1247,6 +1258,40 @@ class ServerInstance:
|
||||
)
|
||||
update_thread.start()
|
||||
|
||||
def write_player_cache(self):
|
||||
write_json = {}
|
||||
for item in self.player_cache:
|
||||
write_json[item["name"]] = item
|
||||
with open(
|
||||
os.path.join(self.server_path, "db_stats", "players_cache.json"),
|
||||
"w",
|
||||
encoding="utf-8",
|
||||
) as f:
|
||||
f.write(json.dumps(write_json, indent=4))
|
||||
logger.info("Cache file refreshed")
|
||||
|
||||
def cache_players(self):
|
||||
server_players = self.get_server_players()
|
||||
for p in self.player_cache[:]:
|
||||
if p["status"] == "Online" and p["name"] not in server_players:
|
||||
p["status"] = "Offline"
|
||||
p["last_seen"] = datetime.datetime.now().strftime("%d/%m/%Y %H:%M")
|
||||
elif p["name"] in server_players:
|
||||
self.player_cache.remove(p)
|
||||
for player in server_players:
|
||||
if player == "Anonymous Player":
|
||||
# Skip Anonymous Player
|
||||
continue
|
||||
if player in self.player_cache:
|
||||
self.player_cache.remove(player)
|
||||
self.player_cache.append(
|
||||
{
|
||||
"name": player,
|
||||
"status": "Online",
|
||||
"last_seen": datetime.datetime.now().strftime("%d/%m/%Y %H:%M"),
|
||||
}
|
||||
)
|
||||
|
||||
def check_update(self):
|
||||
return self.stats_helper.get_server_stats()["updating"]
|
||||
|
||||
@ -1433,6 +1478,12 @@ class ServerInstance:
|
||||
minutes=self.helper.get_setting("dir_size_poll_freq_minutes"),
|
||||
id=str(self.server_id) + "_dir_poll",
|
||||
)
|
||||
self.dir_scheduler.add_job(
|
||||
self.cache_players,
|
||||
"interval",
|
||||
seconds=5,
|
||||
id=str(self.server_id) + "_players_poll",
|
||||
)
|
||||
|
||||
def calc_dir_size(self):
|
||||
server_dt = HelperServers.get_server_data_by_id(self.server_id)
|
||||
@ -1502,6 +1553,7 @@ class ServerInstance:
|
||||
"created": datetime.datetime.now().strftime(
|
||||
"%Y/%m/%d, %H:%M:%S"
|
||||
),
|
||||
"players_cache": self.player_cache,
|
||||
},
|
||||
)
|
||||
total_players += int(raw_ping_result.get("online"))
|
||||
|
@ -421,6 +421,7 @@ class TasksManager:
|
||||
)
|
||||
for item in jobs:
|
||||
logger.info(f"JOB: {item}")
|
||||
return task.schedule_id
|
||||
|
||||
def remove_all_server_tasks(self, server_id):
|
||||
schedules = HelpersManagement.get_schedules_by_server(server_id)
|
||||
@ -450,7 +451,6 @@ class TasksManager:
|
||||
# created task a child of itself.
|
||||
if str(job_data.get("parent")) == str(sch_id):
|
||||
job_data["parent"] = None
|
||||
|
||||
HelpersManagement.update_scheduled_task(sch_id, job_data)
|
||||
|
||||
if not (
|
||||
@ -775,6 +775,7 @@ class TasksManager:
|
||||
def check_for_old_logs(self):
|
||||
# check for server logs first
|
||||
self.controller.servers.check_for_old_logs()
|
||||
try:
|
||||
# check for crafty logs now
|
||||
logs_path = os.path.join(self.controller.project_root, "logs")
|
||||
logs_delete_after = int(
|
||||
@ -803,3 +804,8 @@ class TasksManager:
|
||||
log_file_path, logs_delete_after
|
||||
):
|
||||
os.remove(log_file_path)
|
||||
except:
|
||||
logger.debug(
|
||||
"Unable to find project root."
|
||||
" If this issue persists please contact support."
|
||||
)
|
||||
|
@ -289,9 +289,9 @@ class AjaxHandler(BaseHandler):
|
||||
logger.warning("Server ID not found in send_command ajax call")
|
||||
Console.warning("Server ID not found in send_command ajax call")
|
||||
|
||||
srv_obj = self.controller.servers.get_server_instance_by_id(server_id)
|
||||
svr_obj = self.controller.servers.get_server_instance_by_id(server_id)
|
||||
|
||||
if command == srv_obj.settings["stop_command"]:
|
||||
if command == svr_obj.settings["stop_command"]:
|
||||
logger.info(
|
||||
"Stop command detected as terminal input - intercepting."
|
||||
+ f"Starting Crafty's stop process for server with id: {server_id}"
|
||||
@ -313,8 +313,8 @@ class AjaxHandler(BaseHandler):
|
||||
)
|
||||
command = None
|
||||
if command:
|
||||
if srv_obj.check_running():
|
||||
srv_obj.send_command(command)
|
||||
if svr_obj.check_running():
|
||||
svr_obj.send_command(command)
|
||||
|
||||
self.controller.management.add_to_audit_log(
|
||||
exec_user["user_id"],
|
||||
@ -382,23 +382,6 @@ class AjaxHandler(BaseHandler):
|
||||
self.controller.cached_login = "login_1.jpg"
|
||||
return
|
||||
|
||||
elif page == "kill":
|
||||
if not permissions["Commands"] in user_perms:
|
||||
if not superuser:
|
||||
self.redirect("/panel/error?error=Unauthorized access to Commands")
|
||||
return
|
||||
server_id = self.get_argument("id", None)
|
||||
svr = self.controller.servers.get_server_instance_by_id(server_id)
|
||||
try:
|
||||
svr.kill()
|
||||
time.sleep(5)
|
||||
svr.cleanup_server_object()
|
||||
svr.record_server_stats()
|
||||
except Exception as e:
|
||||
logger.error(
|
||||
f"Could not find PID for requested termsig. Full error: {e}"
|
||||
)
|
||||
return
|
||||
elif page == "eula":
|
||||
server_id = self.get_argument("id", None)
|
||||
svr = self.controller.servers.get_server_instance_by_id(server_id)
|
||||
@ -445,6 +428,21 @@ class AjaxHandler(BaseHandler):
|
||||
new_server_id
|
||||
)
|
||||
new_server_obj.execution_command = server_data["execution_command"]
|
||||
# reset executable path
|
||||
if svr_obj.path in svr_obj.executable:
|
||||
new_server_obj.executable = str(svr_obj.executable).replace(
|
||||
svr_obj.path, new_server_obj.path
|
||||
)
|
||||
# reset run command path
|
||||
if svr_obj.path in svr_obj.execution_command:
|
||||
new_server_obj.execution_command = str(
|
||||
svr_obj.execution_command
|
||||
).replace(svr_obj.path, new_server_obj.path)
|
||||
# reset log path
|
||||
if svr_obj.path in svr_obj.log_path:
|
||||
new_server_obj.log_path = str(svr_obj.log_path).replace(
|
||||
svr_obj.path, new_server_obj.path
|
||||
)
|
||||
self.controller.servers.update_server(new_server_obj)
|
||||
|
||||
# preserve backup config
|
||||
@ -505,6 +503,21 @@ class AjaxHandler(BaseHandler):
|
||||
new_server_id
|
||||
)
|
||||
new_server_obj.execution_command = server_data["execution_command"]
|
||||
# reset executable path
|
||||
if server_obj.path in server_obj.executable:
|
||||
new_server_obj.executable = str(server_obj.executable).replace(
|
||||
server_obj.path, new_server_obj.path
|
||||
)
|
||||
# reset run command path
|
||||
if server_obj.path in server_obj.execution_command:
|
||||
new_server_obj.execution_command = str(
|
||||
server_obj.execution_command
|
||||
).replace(server_obj.path, new_server_obj.path)
|
||||
# reset log path
|
||||
if server_obj.path in server_obj.log_path:
|
||||
new_server_obj.log_path = str(server_obj.log_path).replace(
|
||||
server_obj.path, new_server_obj.path
|
||||
)
|
||||
self.controller.servers.update_server(new_server_obj)
|
||||
|
||||
# preserve backup config
|
||||
@ -624,12 +637,6 @@ class AjaxHandler(BaseHandler):
|
||||
user_perms = self.controller.server_perms.get_user_id_permissions_list(
|
||||
exec_user["user_id"], server_id
|
||||
)
|
||||
if page == "del_task":
|
||||
if not permissions["Schedule"] in user_perms:
|
||||
self.redirect("/panel/error?error=Unauthorized access to Tasks")
|
||||
else:
|
||||
sch_id = self.get_argument("schedule_id", "-404")
|
||||
self.tasks_manager.remove_job(sch_id)
|
||||
|
||||
if page == "del_backup":
|
||||
if not permissions["Backup"] in user_perms:
|
||||
@ -649,12 +656,12 @@ class AjaxHandler(BaseHandler):
|
||||
|
||||
server_info = self.controller.servers.get_server_data_by_id(server_id)
|
||||
if not (
|
||||
Helpers.in_path(
|
||||
Helpers.get_os_understandable_path(server_info["path"]), file_path
|
||||
self.helper.is_subdir(
|
||||
file_path, Helpers.get_os_understandable_path(server_info["path"])
|
||||
)
|
||||
or Helpers.in_path(
|
||||
Helpers.get_os_understandable_path(server_info["backup_path"]),
|
||||
or self.helper.is_subdir(
|
||||
file_path,
|
||||
Helpers.get_os_understandable_path(server_info["backup_path"]),
|
||||
)
|
||||
) or not Helpers.check_file_exists(os.path.abspath(file_path)):
|
||||
logger.warning(f"Invalid path in del_backup ajax call ({file_path})")
|
||||
@ -668,84 +675,6 @@ class AjaxHandler(BaseHandler):
|
||||
):
|
||||
os.remove(file_path)
|
||||
|
||||
elif page == "delete_server":
|
||||
if not permissions["Config"] in user_perms:
|
||||
if not superuser:
|
||||
self.redirect("/panel/error?error=Unauthorized access to Config")
|
||||
return
|
||||
server_id = self.get_argument("id", None)
|
||||
logger.info(
|
||||
f"Removing server from panel for server: "
|
||||
f"{self.controller.servers.get_server_friendly_name(server_id)}"
|
||||
)
|
||||
|
||||
server_data = self.controller.servers.get_server_data(server_id)
|
||||
server_name = server_data["server_name"]
|
||||
|
||||
self.controller.management.add_to_audit_log(
|
||||
exec_user["user_id"],
|
||||
f"Deleted server {server_id} named {server_name}",
|
||||
server_id,
|
||||
self.get_remote_ip(),
|
||||
)
|
||||
|
||||
self.tasks_manager.remove_all_server_tasks(server_id)
|
||||
self.controller.remove_server(server_id, False)
|
||||
|
||||
elif page == "delete_server_files":
|
||||
if not permissions["Config"] in user_perms:
|
||||
if not superuser:
|
||||
self.redirect("/panel/error?error=Unauthorized access to Config")
|
||||
return
|
||||
server_id = self.get_argument("id", None)
|
||||
logger.info(
|
||||
f"Removing server and all associated files for server: "
|
||||
f"{self.controller.servers.get_server_friendly_name(server_id)}"
|
||||
)
|
||||
|
||||
server_data = self.controller.servers.get_server_data(server_id)
|
||||
server_name = server_data["server_name"]
|
||||
|
||||
self.controller.management.add_to_audit_log(
|
||||
exec_user["user_id"],
|
||||
f"Deleted server {server_id} named {server_name}",
|
||||
server_id,
|
||||
self.get_remote_ip(),
|
||||
)
|
||||
|
||||
for server in self.controller.servers.failed_servers:
|
||||
if server["server_id"] == int(server_id):
|
||||
return
|
||||
self.tasks_manager.remove_all_server_tasks(server_id)
|
||||
self.controller.remove_server(server_id, True)
|
||||
|
||||
elif page == "delete_unloaded_server":
|
||||
if not permissions["Config"] in user_perms:
|
||||
if not superuser:
|
||||
self.redirect("/panel/error?error=Unauthorized access to Config")
|
||||
return
|
||||
server_id = self.get_argument("id", None)
|
||||
logger.info(
|
||||
f"Removing server and all associated files for server: "
|
||||
f"{self.controller.servers.get_server_friendly_name(server_id)}"
|
||||
)
|
||||
|
||||
server_data = self.controller.servers.get_server_data_by_id(server_id)
|
||||
server_name = server_data["server_name"]
|
||||
|
||||
self.controller.management.add_to_audit_log(
|
||||
exec_user["user_id"],
|
||||
f"Deleted server {server_id} named {server_name}",
|
||||
server_id,
|
||||
self.get_remote_ip(),
|
||||
)
|
||||
|
||||
self.tasks_manager.remove_all_server_tasks(server_id)
|
||||
for item in self.controller.servers.failed_servers[:]:
|
||||
if item["server_id"] == int(server_id):
|
||||
self.controller.servers.failed_servers.remove(item)
|
||||
self.controller.remove_unloaded_server(server_id)
|
||||
|
||||
def check_server_id(self, server_id, page_name):
|
||||
if server_id is None:
|
||||
logger.warning(
|
||||
|
@ -57,11 +57,11 @@ class FileHandler(BaseHandler):
|
||||
return
|
||||
server_id = bleach.clean(server_id)
|
||||
|
||||
if not Helpers.in_path(
|
||||
if not self.helper.is_subdir(
|
||||
file_path,
|
||||
Helpers.get_os_understandable_path(
|
||||
self.controller.servers.get_server_data_by_id(server_id)["path"]
|
||||
),
|
||||
file_path,
|
||||
) or not Helpers.check_file_exists(os.path.abspath(file_path)):
|
||||
logger.warning(
|
||||
f"Invalid path in get_file file file ajax call ({file_path})"
|
||||
@ -163,11 +163,11 @@ class FileHandler(BaseHandler):
|
||||
return
|
||||
server_id = bleach.clean(server_id)
|
||||
|
||||
if not Helpers.in_path(
|
||||
if not self.helper.is_subdir(
|
||||
file_path,
|
||||
Helpers.get_os_understandable_path(
|
||||
self.controller.servers.get_server_data_by_id(server_id)["path"]
|
||||
),
|
||||
file_path,
|
||||
) or Helpers.check_file_exists(os.path.abspath(file_path)):
|
||||
logger.warning(
|
||||
f"Invalid path in create_file file ajax call ({file_path})"
|
||||
@ -196,11 +196,11 @@ class FileHandler(BaseHandler):
|
||||
return
|
||||
server_id = bleach.clean(server_id)
|
||||
|
||||
if not Helpers.in_path(
|
||||
if not self.helper.is_subdir(
|
||||
dir_path,
|
||||
Helpers.get_os_understandable_path(
|
||||
self.controller.servers.get_server_data_by_id(server_id)["path"]
|
||||
),
|
||||
dir_path,
|
||||
) or Helpers.check_path_exists(os.path.abspath(dir_path)):
|
||||
logger.warning(
|
||||
f"Invalid path in create_dir file ajax call ({dir_path})"
|
||||
@ -263,12 +263,12 @@ class FileHandler(BaseHandler):
|
||||
|
||||
server_info = self.controller.servers.get_server_data_by_id(server_id)
|
||||
if not (
|
||||
Helpers.in_path(
|
||||
Helpers.get_os_understandable_path(server_info["path"]), file_path
|
||||
self.helper.is_subdir(
|
||||
file_path, Helpers.get_os_understandable_path(server_info["path"])
|
||||
)
|
||||
or Helpers.in_path(
|
||||
Helpers.get_os_understandable_path(server_info["backup_path"]),
|
||||
or self.helper.is_subdir(
|
||||
file_path,
|
||||
Helpers.get_os_understandable_path(server_info["backup_path"]),
|
||||
)
|
||||
) or not Helpers.check_file_exists(os.path.abspath(file_path)):
|
||||
logger.warning(f"Invalid path in del_file file ajax call ({file_path})")
|
||||
@ -296,8 +296,8 @@ class FileHandler(BaseHandler):
|
||||
server_id = bleach.clean(server_id)
|
||||
|
||||
server_info = self.controller.servers.get_server_data_by_id(server_id)
|
||||
if not Helpers.in_path(
|
||||
Helpers.get_os_understandable_path(server_info["path"]), dir_path
|
||||
if not self.helper.is_subdir(
|
||||
dir_path, Helpers.get_os_understandable_path(server_info["path"])
|
||||
) or not Helpers.check_path_exists(os.path.abspath(dir_path)):
|
||||
logger.warning(f"Invalid path in del_file file ajax call ({dir_path})")
|
||||
Console.warning(f"Invalid path in del_file file ajax call ({dir_path})")
|
||||
@ -348,11 +348,11 @@ class FileHandler(BaseHandler):
|
||||
return
|
||||
server_id = bleach.clean(server_id)
|
||||
|
||||
if not Helpers.in_path(
|
||||
if not self.helper.is_subdir(
|
||||
file_path,
|
||||
Helpers.get_os_understandable_path(
|
||||
self.controller.servers.get_server_data_by_id(server_id)["path"]
|
||||
),
|
||||
file_path,
|
||||
) or not Helpers.check_file_exists(os.path.abspath(file_path)):
|
||||
logger.warning(
|
||||
f"Invalid path in save_file file ajax call ({file_path})"
|
||||
@ -366,60 +366,6 @@ class FileHandler(BaseHandler):
|
||||
with open(file_path, "w", encoding="utf-8") as file_object:
|
||||
file_object.write(file_contents)
|
||||
|
||||
elif page == "rename_file":
|
||||
if not permissions["Files"] in user_perms:
|
||||
if not superuser:
|
||||
self.redirect("/panel/error?error=Unauthorized access to Files")
|
||||
return
|
||||
item_path = Helpers.get_os_understandable_path(
|
||||
self.get_body_argument("item_path", default=None, strip=True)
|
||||
)
|
||||
new_item_name = self.get_body_argument(
|
||||
"new_item_name", default=None, strip=True
|
||||
)
|
||||
|
||||
if not self.check_server_id(server_id, "rename_file"):
|
||||
return
|
||||
server_id = bleach.clean(server_id)
|
||||
|
||||
if item_path is None or new_item_name is None:
|
||||
logger.warning("Invalid path(s) in rename_file file ajax call")
|
||||
Console.warning("Invalid path(s) in rename_file file ajax call")
|
||||
return
|
||||
|
||||
if not Helpers.in_path(
|
||||
Helpers.get_os_understandable_path(
|
||||
self.controller.servers.get_server_data_by_id(server_id)["path"]
|
||||
),
|
||||
item_path,
|
||||
) or not Helpers.check_path_exists(os.path.abspath(item_path)):
|
||||
logger.warning(
|
||||
f"Invalid old name path in rename_file file ajax call ({server_id})"
|
||||
)
|
||||
Console.warning(
|
||||
f"Invalid old name path in rename_file file ajax call ({server_id})"
|
||||
)
|
||||
return
|
||||
|
||||
new_item_path = os.path.join(os.path.split(item_path)[0], new_item_name)
|
||||
|
||||
if not Helpers.in_path(
|
||||
Helpers.get_os_understandable_path(
|
||||
self.controller.servers.get_server_data_by_id(server_id)["path"]
|
||||
),
|
||||
new_item_path,
|
||||
) or Helpers.check_path_exists(os.path.abspath(new_item_path)):
|
||||
logger.warning(
|
||||
f"Invalid new name path in rename_file file ajax call ({server_id})"
|
||||
)
|
||||
Console.warning(
|
||||
f"Invalid new name path in rename_file file ajax call ({server_id})"
|
||||
)
|
||||
return
|
||||
|
||||
# RENAME
|
||||
os.rename(item_path, new_item_path)
|
||||
|
||||
@tornado.web.authenticated
|
||||
def patch(self, page):
|
||||
api_key, _, exec_user = self.current_user
|
||||
@ -462,11 +408,11 @@ class FileHandler(BaseHandler):
|
||||
Console.warning("Invalid path(s) in rename_file file ajax call")
|
||||
return
|
||||
|
||||
if not Helpers.in_path(
|
||||
if not self.helper.is_subdir(
|
||||
item_path,
|
||||
Helpers.get_os_understandable_path(
|
||||
self.controller.servers.get_server_data_by_id(server_id)["path"]
|
||||
),
|
||||
item_path,
|
||||
) or not Helpers.check_path_exists(os.path.abspath(item_path)):
|
||||
logger.warning(
|
||||
f"Invalid old name path in rename_file file ajax call ({server_id})"
|
||||
@ -478,11 +424,11 @@ class FileHandler(BaseHandler):
|
||||
|
||||
new_item_path = os.path.join(os.path.split(item_path)[0], new_item_name)
|
||||
|
||||
if not Helpers.in_path(
|
||||
if not self.helper.is_subdir(
|
||||
new_item_path,
|
||||
Helpers.get_os_understandable_path(
|
||||
self.controller.servers.get_server_data_by_id(server_id)["path"]
|
||||
),
|
||||
new_item_path,
|
||||
) or Helpers.check_path_exists(os.path.abspath(new_item_path)):
|
||||
logger.warning(
|
||||
f"Invalid new name path in rename_file file ajax call ({server_id})"
|
||||
|
@ -6,7 +6,6 @@ import typing as t
|
||||
import json
|
||||
import logging
|
||||
import threading
|
||||
import shlex
|
||||
import urllib.parse
|
||||
import bleach
|
||||
import requests
|
||||
@ -17,7 +16,6 @@ from tornado import iostream
|
||||
# TZLocal is set as a hidden import on win pipeline
|
||||
from tzlocal import get_localzone
|
||||
from tzlocal.utils import ZoneInfoNotFoundError
|
||||
from croniter import croniter
|
||||
|
||||
from app.classes.models.servers import Servers
|
||||
from app.classes.models.server_permissions import EnumPermissionsServer
|
||||
@ -256,7 +254,12 @@ class PanelHandler(BaseHandler):
|
||||
user_order = user_order["server_order"].split(",")
|
||||
page_servers = []
|
||||
server_ids = []
|
||||
|
||||
for server in defined_servers:
|
||||
server_ids.append(str(server.server_id))
|
||||
if str(server.server_id) not in user_order:
|
||||
# a little unorthodox, but this will cut out a loop.
|
||||
# adding servers to the user order that don't already exist there.
|
||||
user_order.append(str(server.server_id))
|
||||
for server_id in user_order[:]:
|
||||
for server in defined_servers[:]:
|
||||
if str(server.server_id) == str(server_id):
|
||||
@ -265,14 +268,7 @@ class PanelHandler(BaseHandler):
|
||||
)
|
||||
user_order.remove(server_id)
|
||||
defined_servers.remove(server)
|
||||
|
||||
for server in defined_servers:
|
||||
server_ids.append(str(server.server_id))
|
||||
if server not in page_servers:
|
||||
page_servers.append(
|
||||
DatabaseShortcuts.get_data_obj(server.server_object)
|
||||
)
|
||||
|
||||
break
|
||||
for server_id in user_order[:]:
|
||||
# remove IDs in list that user no longer has access to
|
||||
if str(server_id) not in server_ids:
|
||||
@ -452,6 +448,7 @@ class PanelHandler(BaseHandler):
|
||||
page_servers.append(server)
|
||||
un_used_servers.remove(server)
|
||||
user_order.remove(server_id)
|
||||
break
|
||||
# we only want to set these server stats values once.
|
||||
# We need to update the flag so it only hits that if once.
|
||||
flag += 1
|
||||
@ -780,7 +777,21 @@ class PanelHandler(BaseHandler):
|
||||
):
|
||||
if not superuser:
|
||||
self.redirect("/panel/error?error=Unauthorized access")
|
||||
page_data["banned_players"] = get_banned_players_html()
|
||||
page_data["banned_players_html"] = get_banned_players_html()
|
||||
page_data[
|
||||
"banned_players"
|
||||
] = self.controller.servers.get_banned_players(server_id)
|
||||
server_instance = self.controller.servers.get_server_instance_by_id(
|
||||
server_id
|
||||
)
|
||||
page_data["cached_players"] = server_instance.player_cache
|
||||
|
||||
for player in page_data["banned_players"]:
|
||||
player["banned"] = True
|
||||
temp_date = datetime.datetime.strptime(
|
||||
player["created"], "%Y-%m-%d %H:%M:%S %z"
|
||||
)
|
||||
player["banned_on"] = (temp_date).strftime("%Y/%m/%d %H:%M:%S")
|
||||
|
||||
template = f"panel/server_{subpage}.html"
|
||||
|
||||
@ -797,9 +808,9 @@ class PanelHandler(BaseHandler):
|
||||
Helpers.get_os_understandable_path(server_info["backup_path"]), file
|
||||
)
|
||||
)
|
||||
if not Helpers.in_path(
|
||||
Helpers.get_os_understandable_path(server_info["backup_path"]),
|
||||
if not self.helper.is_subdir(
|
||||
backup_file,
|
||||
Helpers.get_os_understandable_path(server_info["backup_path"]),
|
||||
) or not os.path.isfile(backup_file):
|
||||
self.redirect("/panel/error?error=Invalid path detected")
|
||||
return
|
||||
@ -1053,7 +1064,7 @@ class PanelHandler(BaseHandler):
|
||||
page_data["schedule"]["cron_string"] = ""
|
||||
page_data["schedule"]["delay"] = 0
|
||||
page_data["schedule"]["time"] = ""
|
||||
page_data["schedule"]["interval"] = ""
|
||||
page_data["schedule"]["interval"] = 1
|
||||
# we don't need to check difficulty here.
|
||||
# We'll just default to basic for new schedules
|
||||
page_data["schedule"]["difficulty"] = "basic"
|
||||
@ -1452,8 +1463,9 @@ class PanelHandler(BaseHandler):
|
||||
|
||||
server_info = self.controller.servers.get_server_data_by_id(server_id)
|
||||
|
||||
if not Helpers.in_path(
|
||||
Helpers.get_os_understandable_path(server_info["path"]), file
|
||||
if not self.helper.is_subdir(
|
||||
file,
|
||||
Helpers.get_os_understandable_path(server_info["path"]),
|
||||
) or not os.path.isfile(file):
|
||||
self.redirect("/panel/error?error=Invalid path detected")
|
||||
return
|
||||
@ -1556,156 +1568,6 @@ class PanelHandler(BaseHandler):
|
||||
role = self.controller.roles.get_role(r)
|
||||
exec_user_role.add(role["role_name"])
|
||||
|
||||
if page == "server_detail":
|
||||
if not permissions[
|
||||
"Config"
|
||||
] in self.controller.server_perms.get_user_id_permissions_list(
|
||||
exec_user["user_id"], server_id
|
||||
):
|
||||
if not superuser:
|
||||
self.redirect("/panel/error?error=Unauthorized access to Config")
|
||||
return
|
||||
server_name = self.get_argument("server_name", None)
|
||||
server_obj = self.controller.servers.get_server_obj(server_id)
|
||||
shutdown_timeout = self.get_argument("shutdown_timeout", 60)
|
||||
if superuser:
|
||||
log_path = self.get_argument("log_path", "")
|
||||
if log_path:
|
||||
if Helpers.is_os_windows():
|
||||
log_path.replace(" ", "^ ")
|
||||
log_path = Helpers.wtol_path(log_path)
|
||||
if not self.helper.validate_traversal(server_obj.path, log_path):
|
||||
log_path = ""
|
||||
executable = self.get_argument("executable", None)
|
||||
execution_command = self.get_argument("execution_command", None)
|
||||
server_ip = self.get_argument("server_ip", None)
|
||||
server_port = self.get_argument("server_port", None)
|
||||
if int(server_port) < 1 or int(server_port) > 65535:
|
||||
self.redirect(
|
||||
"/panel/error?error=Constraint Error: "
|
||||
"Port must be greater than 0 and less than 65535"
|
||||
)
|
||||
return
|
||||
executable_update_url = self.get_argument("executable_update_url", "")
|
||||
show_status = int(float(self.get_argument("show_status", "0")))
|
||||
else:
|
||||
execution_command = server_obj.execution_command
|
||||
executable = server_obj.executable
|
||||
stop_command = self.get_argument("stop_command", None)
|
||||
auto_start_delay = self.get_argument("auto_start_delay", "10")
|
||||
auto_start = int(float(self.get_argument("auto_start", "0")))
|
||||
crash_detection = int(float(self.get_argument("crash_detection", "0")))
|
||||
logs_delete_after = int(float(self.get_argument("logs_delete_after", "0")))
|
||||
java_selection = self.get_argument("java_selection", None)
|
||||
# make sure there is no whitespace
|
||||
ignored_exits = self.get_argument("ignored_exits", "").replace(" ", "")
|
||||
# subpage = self.get_argument('subpage', None)
|
||||
|
||||
server_id = self.check_server_id()
|
||||
if server_id is None:
|
||||
return
|
||||
if java_selection:
|
||||
try:
|
||||
if self.helper.is_os_windows():
|
||||
execution_list = shlex.split(execution_command, posix=False)
|
||||
else:
|
||||
execution_list = shlex.split(execution_command, posix=True)
|
||||
except ValueError:
|
||||
self.redirect(
|
||||
"/panel/error?error=Invalid execution command. Java path"
|
||||
" must be surrounded by quotes."
|
||||
" (Are you missing a closing quote?)"
|
||||
)
|
||||
if (
|
||||
not any(
|
||||
java_selection in path for path in Helpers.find_java_installs()
|
||||
)
|
||||
and java_selection != "java"
|
||||
):
|
||||
self.redirect(
|
||||
"/panel/error?error=Attack attempted."
|
||||
+ " A copy of this report is being sent to server owner."
|
||||
)
|
||||
self.controller.management.add_to_audit_log_raw(
|
||||
exec_user["username"],
|
||||
exec_user["user_id"],
|
||||
server_id,
|
||||
f"Attempted to send bad java path for {server_id}."
|
||||
+ " Possible attack. Act accordingly.",
|
||||
self.get_remote_ip(),
|
||||
)
|
||||
return
|
||||
if java_selection != "java":
|
||||
if self.helper.is_os_windows():
|
||||
execution_list[0] = '"' + java_selection + '/bin/java"'
|
||||
else:
|
||||
execution_list[0] = '"' + java_selection + '"'
|
||||
else:
|
||||
execution_list[0] = "java"
|
||||
execution_command = ""
|
||||
for item in execution_list:
|
||||
execution_command += item + " "
|
||||
|
||||
server_obj: Servers = self.controller.servers.get_server_obj(server_id)
|
||||
stale_executable = server_obj.executable
|
||||
# Compares old jar name to page data being passed.
|
||||
# If they are different we replace the executable name in the
|
||||
if str(stale_executable) != str(executable):
|
||||
execution_command = execution_command.replace(
|
||||
str(stale_executable), str(executable)
|
||||
)
|
||||
|
||||
server_obj.server_name = server_name
|
||||
server_obj.shutdown_timeout = shutdown_timeout
|
||||
if superuser:
|
||||
if Helpers.validate_traversal(
|
||||
self.helper.get_servers_root_dir(), server_obj.path
|
||||
):
|
||||
server_obj.log_path = log_path
|
||||
if Helpers.validate_traversal(
|
||||
self.helper.get_servers_root_dir(), executable
|
||||
):
|
||||
server_obj.executable = executable
|
||||
server_obj.execution_command = execution_command
|
||||
server_obj.server_ip = server_ip
|
||||
server_obj.server_port = server_port
|
||||
server_obj.executable_update_url = executable_update_url
|
||||
server_obj.show_status = show_status
|
||||
else:
|
||||
server_obj.log_path = server_obj.log_path
|
||||
server_obj.executable = server_obj.executable
|
||||
server_obj.execution_command = execution_command
|
||||
server_obj.server_ip = server_obj.server_ip
|
||||
server_obj.server_port = server_obj.server_port
|
||||
server_obj.executable_update_url = server_obj.executable_update_url
|
||||
server_obj.stop_command = stop_command
|
||||
server_obj.auto_start_delay = auto_start_delay
|
||||
server_obj.auto_start = auto_start
|
||||
server_obj.crash_detection = crash_detection
|
||||
server_obj.logs_delete_after = logs_delete_after
|
||||
server_obj.ignored_exits = ignored_exits
|
||||
failed = False
|
||||
for servers in self.controller.servers.failed_servers:
|
||||
if servers["server_id"] == int(server_id):
|
||||
failed = True
|
||||
if not failed:
|
||||
self.controller.servers.update_server(server_obj)
|
||||
else:
|
||||
self.controller.servers.update_unloaded_server(server_obj)
|
||||
self.controller.servers.init_all_servers()
|
||||
self.controller.servers.crash_detection(server_obj)
|
||||
|
||||
self.controller.servers.refresh_server_settings(server_id)
|
||||
|
||||
self.controller.management.add_to_audit_log(
|
||||
exec_user["user_id"],
|
||||
f"Edited server {server_id} named {server_name}",
|
||||
server_id,
|
||||
self.get_remote_ip(),
|
||||
)
|
||||
|
||||
self.redirect(f"/panel/server_detail?id={server_id}&subpage=config")
|
||||
|
||||
if page == "server_backup":
|
||||
logger.debug(self.request.arguments)
|
||||
|
||||
@ -1802,336 +1664,6 @@ class PanelHandler(BaseHandler):
|
||||
|
||||
self.redirect("/panel/config_json")
|
||||
|
||||
if page == "new_schedule":
|
||||
server_id = self.check_server_id()
|
||||
if not server_id:
|
||||
return
|
||||
|
||||
if (
|
||||
not permissions["Schedule"]
|
||||
in self.controller.server_perms.get_user_id_permissions_list(
|
||||
exec_user["user_id"], server_id
|
||||
)
|
||||
and not superuser
|
||||
):
|
||||
self.redirect(
|
||||
"/panel/error?error=Unauthorized access: User not authorized"
|
||||
)
|
||||
return
|
||||
|
||||
difficulty = bleach.clean(self.get_argument("difficulty", None))
|
||||
server_obj = self.controller.servers.get_server_obj(server_id)
|
||||
enabled = bleach.clean(self.get_argument("enabled", "0"))
|
||||
name = bleach.clean(self.get_argument("name", ""))
|
||||
if difficulty == "basic":
|
||||
action = bleach.clean(self.get_argument("action", None))
|
||||
interval = bleach.clean(self.get_argument("interval", None))
|
||||
interval_type = bleach.clean(self.get_argument("interval_type", None))
|
||||
# only check for time if it's number of days
|
||||
if interval_type == "days":
|
||||
sch_time = bleach.clean(self.get_argument("time", None))
|
||||
if int(interval) > 30:
|
||||
self.redirect(
|
||||
"/panel/error?error=Invalid argument."
|
||||
" Days must be 30 or fewer."
|
||||
)
|
||||
return
|
||||
if action == "command":
|
||||
command = self.get_argument("command", None)
|
||||
elif action == "start":
|
||||
command = "start_server"
|
||||
elif action == "stop":
|
||||
command = "stop_server"
|
||||
elif action == "restart":
|
||||
command = "restart_server"
|
||||
elif action == "backup":
|
||||
command = "backup_server"
|
||||
|
||||
elif difficulty == "reaction":
|
||||
interval_type = "reaction"
|
||||
action = bleach.clean(self.get_argument("action", None))
|
||||
delay = bleach.clean(self.get_argument("delay", None))
|
||||
parent = bleach.clean(self.get_argument("parent", None))
|
||||
if action == "command":
|
||||
command = self.get_argument("command", None)
|
||||
elif action == "start":
|
||||
command = "start_server"
|
||||
elif action == "stop":
|
||||
command = "stop_server"
|
||||
elif action == "restart":
|
||||
command = "restart_server"
|
||||
elif action == "backup":
|
||||
command = "backup_server"
|
||||
|
||||
else:
|
||||
interval_type = ""
|
||||
cron_string = bleach.clean(self.get_argument("cron", ""))
|
||||
if not croniter.is_valid(cron_string):
|
||||
self.redirect(
|
||||
"/panel/error?error=INVALID FORMAT: Invalid Cron Format."
|
||||
)
|
||||
return
|
||||
action = bleach.clean(self.get_argument("action", None))
|
||||
if action == "command":
|
||||
command = self.get_argument("command", None)
|
||||
elif action == "start":
|
||||
command = "start_server"
|
||||
elif action == "stop":
|
||||
command = "stop_server"
|
||||
elif action == "restart":
|
||||
command = "restart_server"
|
||||
elif action == "backup":
|
||||
command = "backup_server"
|
||||
if bleach.clean(self.get_argument("enabled", "0")) == "1":
|
||||
enabled = True
|
||||
else:
|
||||
enabled = False
|
||||
if bleach.clean(self.get_argument("one_time", "0")) == "1":
|
||||
one_time = True
|
||||
else:
|
||||
one_time = False
|
||||
|
||||
if interval_type == "days":
|
||||
job_data = {
|
||||
"name": name,
|
||||
"server_id": server_id,
|
||||
"action": action,
|
||||
"interval_type": interval_type,
|
||||
"interval": interval,
|
||||
"command": command,
|
||||
"start_time": sch_time,
|
||||
"enabled": enabled,
|
||||
"one_time": one_time,
|
||||
"cron_string": "",
|
||||
"parent": None,
|
||||
"delay": 0,
|
||||
}
|
||||
elif difficulty == "reaction":
|
||||
job_data = {
|
||||
"name": name,
|
||||
"server_id": server_id,
|
||||
"action": action,
|
||||
"interval_type": interval_type,
|
||||
"interval": "",
|
||||
# We'll base every interval off of a midnight start time.
|
||||
"start_time": "",
|
||||
"command": command,
|
||||
"cron_string": "",
|
||||
"enabled": enabled,
|
||||
"one_time": one_time,
|
||||
"parent": parent,
|
||||
"delay": delay,
|
||||
}
|
||||
elif difficulty == "advanced":
|
||||
job_data = {
|
||||
"name": name,
|
||||
"server_id": server_id,
|
||||
"action": action,
|
||||
"interval_type": "",
|
||||
"interval": "",
|
||||
# We'll base every interval off of a midnight start time.
|
||||
"start_time": "",
|
||||
"command": command,
|
||||
"cron_string": cron_string,
|
||||
"enabled": enabled,
|
||||
"one_time": one_time,
|
||||
"parent": None,
|
||||
"delay": 0,
|
||||
}
|
||||
else:
|
||||
job_data = {
|
||||
"name": name,
|
||||
"server_id": server_id,
|
||||
"action": action,
|
||||
"interval_type": interval_type,
|
||||
"interval": interval,
|
||||
"command": command,
|
||||
"enabled": enabled,
|
||||
# We'll base every interval off of a midnight start time.
|
||||
"start_time": "00:00",
|
||||
"one_time": one_time,
|
||||
"cron_string": "",
|
||||
"parent": None,
|
||||
"delay": 0,
|
||||
}
|
||||
|
||||
self.tasks_manager.schedule_job(job_data)
|
||||
|
||||
self.controller.management.add_to_audit_log(
|
||||
exec_user["user_id"],
|
||||
f"Edited server {server_id}: added scheduled job",
|
||||
server_id,
|
||||
self.get_remote_ip(),
|
||||
)
|
||||
self.tasks_manager.reload_schedule_from_db()
|
||||
self.redirect(f"/panel/server_detail?id={server_id}&subpage=schedules")
|
||||
|
||||
if page == "edit_schedule":
|
||||
server_id = self.check_server_id()
|
||||
if not server_id:
|
||||
return
|
||||
|
||||
if (
|
||||
not permissions["Schedule"]
|
||||
in self.controller.server_perms.get_user_id_permissions_list(
|
||||
exec_user["user_id"], server_id
|
||||
)
|
||||
and not superuser
|
||||
):
|
||||
self.redirect(
|
||||
"/panel/error?error=Unauthorized access: User not authorized"
|
||||
)
|
||||
return
|
||||
|
||||
sch_id = self.get_argument("sch_id", None)
|
||||
if sch_id is None:
|
||||
self.redirect("/panel/error?error=Invalid Schedule ID")
|
||||
|
||||
difficulty = bleach.clean(self.get_argument("difficulty", None))
|
||||
server_obj = self.controller.servers.get_server_obj(server_id)
|
||||
enabled = bleach.clean(self.get_argument("enabled", "0"))
|
||||
name = bleach.clean(self.get_argument("name", ""))
|
||||
if difficulty == "basic":
|
||||
action = bleach.clean(self.get_argument("action", None))
|
||||
interval = bleach.clean(self.get_argument("interval", None))
|
||||
interval_type = bleach.clean(self.get_argument("interval_type", None))
|
||||
# only check for time if it's number of days
|
||||
if interval_type == "days":
|
||||
sch_time = bleach.clean(self.get_argument("time", None))
|
||||
if int(interval) > 30:
|
||||
self.redirect(
|
||||
"/panel/error?error=Invalid argument."
|
||||
" Days must be 30 or fewer."
|
||||
)
|
||||
return
|
||||
if action == "command":
|
||||
command = self.get_argument("command", None)
|
||||
elif action == "start":
|
||||
command = "start_server"
|
||||
elif action == "stop":
|
||||
command = "stop_server"
|
||||
elif action == "restart":
|
||||
command = "restart_server"
|
||||
elif action == "backup":
|
||||
command = "backup_server"
|
||||
elif difficulty == "reaction":
|
||||
interval_type = "reaction"
|
||||
action = bleach.clean(self.get_argument("action", None))
|
||||
delay = bleach.clean(self.get_argument("delay", None))
|
||||
parent = bleach.clean(self.get_argument("parent", None))
|
||||
if action == "command":
|
||||
command = self.get_argument("command", None)
|
||||
elif action == "start":
|
||||
command = "start_server"
|
||||
elif action == "stop":
|
||||
command = "stop_server"
|
||||
elif action == "restart":
|
||||
command = "restart_server"
|
||||
elif action == "backup":
|
||||
command = "backup_server"
|
||||
parent = bleach.clean(self.get_argument("parent", None))
|
||||
else:
|
||||
interval_type = ""
|
||||
cron_string = bleach.clean(self.get_argument("cron", ""))
|
||||
if not croniter.is_valid(cron_string):
|
||||
self.redirect(
|
||||
"/panel/error?error=INVALID FORMAT: Invalid Cron Format."
|
||||
)
|
||||
return
|
||||
action = bleach.clean(self.get_argument("action", None))
|
||||
if action == "command":
|
||||
command = self.get_argument("command", None)
|
||||
elif action == "start":
|
||||
command = "start_server"
|
||||
elif action == "stop":
|
||||
command = "stop_server"
|
||||
elif action == "restart":
|
||||
command = "restart_server"
|
||||
elif action == "backup":
|
||||
command = "backup_server"
|
||||
if bleach.clean(self.get_argument("enabled", "0")) == "1":
|
||||
enabled = True
|
||||
else:
|
||||
enabled = False
|
||||
if bleach.clean(self.get_argument("one_time", "0")) == "1":
|
||||
one_time = True
|
||||
else:
|
||||
one_time = False
|
||||
|
||||
if interval_type == "days":
|
||||
job_data = {
|
||||
"name": name,
|
||||
"server_id": server_id,
|
||||
"action": action,
|
||||
"interval_type": interval_type,
|
||||
"interval": interval,
|
||||
"command": command,
|
||||
"start_time": sch_time,
|
||||
"enabled": enabled,
|
||||
"one_time": one_time,
|
||||
"cron_string": "",
|
||||
"parent": None,
|
||||
"delay": 0,
|
||||
}
|
||||
elif difficulty == "advanced":
|
||||
job_data = {
|
||||
"name": name,
|
||||
"server_id": server_id,
|
||||
"action": action,
|
||||
"interval_type": "",
|
||||
"interval": "",
|
||||
# We'll base every interval off of a midnight start time.
|
||||
"start_time": "",
|
||||
"command": command,
|
||||
"cron_string": cron_string,
|
||||
"delay": "",
|
||||
"parent": "",
|
||||
"enabled": enabled,
|
||||
"one_time": one_time,
|
||||
}
|
||||
elif difficulty == "reaction":
|
||||
job_data = {
|
||||
"name": name,
|
||||
"server_id": server_id,
|
||||
"action": action,
|
||||
"interval_type": interval_type,
|
||||
"interval": "",
|
||||
# We'll base every interval off of a midnight start time.
|
||||
"start_time": "",
|
||||
"command": command,
|
||||
"cron_string": "",
|
||||
"enabled": enabled,
|
||||
"one_time": one_time,
|
||||
"parent": parent,
|
||||
"delay": delay,
|
||||
}
|
||||
else:
|
||||
job_data = {
|
||||
"name": name,
|
||||
"server_id": server_id,
|
||||
"action": action,
|
||||
"interval_type": interval_type,
|
||||
"interval": interval,
|
||||
"command": command,
|
||||
"enabled": enabled,
|
||||
# We'll base every interval off of a midnight start time.
|
||||
"start_time": "00:00",
|
||||
"delay": "",
|
||||
"parent": "",
|
||||
"one_time": one_time,
|
||||
"cron_string": "",
|
||||
}
|
||||
self.tasks_manager.update_job(sch_id, job_data)
|
||||
|
||||
self.controller.management.add_to_audit_log(
|
||||
exec_user["user_id"],
|
||||
f"Edited server {server_id}: updated schedule",
|
||||
server_id,
|
||||
self.get_remote_ip(),
|
||||
)
|
||||
self.tasks_manager.reload_schedule_from_db()
|
||||
self.redirect(f"/panel/server_detail?id={server_id}&subpage=schedules")
|
||||
|
||||
elif page == "edit_user":
|
||||
if bleach.clean(self.get_argument("username", None)).lower() == "system":
|
||||
self.redirect(
|
||||
|
@ -50,12 +50,15 @@ class PublicHandler(BaseHandler):
|
||||
if page == "login":
|
||||
template = "public/login.html"
|
||||
|
||||
elif page == 404:
|
||||
elif page == "404":
|
||||
template = "public/404.html"
|
||||
|
||||
elif page == "error":
|
||||
template = "public/error.html"
|
||||
|
||||
elif page == "offline":
|
||||
template = "public/offline.html"
|
||||
|
||||
elif page == "logout":
|
||||
self.clear_cookie("token")
|
||||
# self.clear_cookie("user")
|
||||
|
@ -4,6 +4,36 @@ from peewee import DoesNotExist
|
||||
from app.classes.web.base_api_handler import BaseApiHandler
|
||||
|
||||
modify_role_schema = {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
},
|
||||
"servers": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"server_id": {
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
},
|
||||
"permissions": {
|
||||
"type": "string",
|
||||
"pattern": "^[01]{8}$", # 8 bits, see EnumPermissionsServer
|
||||
},
|
||||
},
|
||||
"required": ["server_id", "permissions"],
|
||||
},
|
||||
},
|
||||
"manager": {"type": ["integer", "null"]},
|
||||
},
|
||||
"additionalProperties": False,
|
||||
"minProperties": 1,
|
||||
}
|
||||
|
||||
basic_modify_role_schema = {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
@ -109,7 +139,10 @@ class ApiRolesRoleIndexHandler(BaseApiHandler):
|
||||
)
|
||||
|
||||
try:
|
||||
if auth_data[4]["superuser"]:
|
||||
validate(data, modify_role_schema)
|
||||
else:
|
||||
validate(data, basic_modify_role_schema)
|
||||
except ValidationError as e:
|
||||
return self.finish_json(
|
||||
400,
|
||||
|
@ -13,20 +13,39 @@ server_patch_schema = {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"server_name": {"type": "string", "minLength": 1},
|
||||
"path": {"type": "string", "minLength": 1},
|
||||
"backup_path": {"type": "string"},
|
||||
"executable": {"type": "string"},
|
||||
"log_path": {"type": "string", "minLength": 1},
|
||||
"execution_command": {"type": "string", "minLength": 1},
|
||||
"java_selection": {"type": "string"},
|
||||
"auto_start": {"type": "boolean"},
|
||||
"auto_start_delay": {"type": "integer"},
|
||||
"auto_start_delay": {"type": "integer", "minimum": 0},
|
||||
"crash_detection": {"type": "boolean"},
|
||||
"stop_command": {"type": "string"},
|
||||
"executable_update_url": {"type": "string", "minLength": 1},
|
||||
"executable_update_url": {"type": "string"},
|
||||
"server_ip": {"type": "string", "minLength": 1},
|
||||
"server_port": {"type": "integer"},
|
||||
"logs_delete_after": {"type": "integer"},
|
||||
"type": {"type": "string", "minLength": 1},
|
||||
"shutdown_timeout": {"type": "integer", "minimum": 0},
|
||||
"logs_delete_after": {"type": "integer", "minimum": 0},
|
||||
"ignored_exits": {"type": "string"},
|
||||
"show_status": {"type": "boolean"},
|
||||
},
|
||||
"additionalProperties": False,
|
||||
"minProperties": 1,
|
||||
}
|
||||
basic_server_patch_schema = {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"server_name": {"type": "string", "minLength": 1},
|
||||
"executable": {"type": "string"},
|
||||
"java_selection": {"type": "string"},
|
||||
"auto_start": {"type": "boolean"},
|
||||
"auto_start_delay": {"type": "integer", "minimum": 0},
|
||||
"crash_detection": {"type": "boolean"},
|
||||
"stop_command": {"type": "string"},
|
||||
"shutdown_timeout": {"type": "integer"},
|
||||
"logs_delete_after": {"type": "integer", "minimum": 0},
|
||||
"ignored_exits": {"type": "string"},
|
||||
},
|
||||
"additionalProperties": False,
|
||||
"minProperties": 1,
|
||||
@ -63,7 +82,11 @@ class ApiServersServerIndexHandler(BaseApiHandler):
|
||||
)
|
||||
|
||||
try:
|
||||
# prevent general users from becoming bad actors
|
||||
if auth_data[4]["superuser"]:
|
||||
validate(data, server_patch_schema)
|
||||
else:
|
||||
validate(data, basic_server_patch_schema)
|
||||
except ValidationError as e:
|
||||
return self.finish_json(
|
||||
400,
|
||||
@ -88,9 +111,24 @@ class ApiServersServerIndexHandler(BaseApiHandler):
|
||||
return self.finish_json(400, {"status": "error", "error": "NOT_AUTHORIZED"})
|
||||
|
||||
server_obj = self.controller.servers.get_server_obj(server_id)
|
||||
java_flag = False
|
||||
for key in data:
|
||||
# If we don't validate the input there could be security issues
|
||||
if key == "java_selection" and data[key] != "none":
|
||||
try:
|
||||
command = self.helper.get_execution_java(
|
||||
data[key], server_obj.execution_command
|
||||
)
|
||||
setattr(server_obj, "execution_command", command)
|
||||
except ValueError:
|
||||
return self.finish_json(
|
||||
400, {"status": "error", "error": "INVALID EXECUTION COMMAND"}
|
||||
)
|
||||
java_flag = True
|
||||
|
||||
if key != "path":
|
||||
if key == "execution_command" and java_flag:
|
||||
continue
|
||||
setattr(server_obj, key, data[key])
|
||||
self.controller.servers.update_server(server_obj)
|
||||
|
||||
@ -134,6 +172,15 @@ class ApiServersServerIndexHandler(BaseApiHandler):
|
||||
)
|
||||
|
||||
self.tasks_manager.remove_all_server_tasks(server_id)
|
||||
failed = False
|
||||
for item in self.controller.servers.failed_servers[:]:
|
||||
if item["server_id"] == int(server_id):
|
||||
self.controller.servers.failed_servers.remove(item)
|
||||
failed = True
|
||||
|
||||
if failed:
|
||||
self.controller.remove_unloaded_server(server_id)
|
||||
else:
|
||||
self.controller.remove_server(server_id, remove_files)
|
||||
|
||||
self.controller.management.add_to_audit_log(
|
||||
|
@ -35,7 +35,13 @@ class ApiServersServerStdinHandler(BaseApiHandler):
|
||||
"Please report this to the devs"
|
||||
)
|
||||
return self.finish_json(400, {"status": "error", "error": "NOT_AUTHORIZED"})
|
||||
|
||||
decoded = self.request.body.decode("utf-8")
|
||||
self.controller.management.add_to_audit_log(
|
||||
auth_data[4]["user_id"],
|
||||
f"Sent command ({decoded}) to terminal",
|
||||
server_id=0,
|
||||
source_ip=self.get_remote_ip(),
|
||||
)
|
||||
if svr.send_command(self.request.body.decode("utf-8")):
|
||||
return self.finish_json(
|
||||
200,
|
||||
|
@ -1,16 +1,122 @@
|
||||
# TODO: create and read
|
||||
|
||||
import json
|
||||
import logging
|
||||
|
||||
from croniter import croniter
|
||||
from jsonschema import ValidationError, validate
|
||||
from app.classes.models.server_permissions import EnumPermissionsServer
|
||||
from app.classes.web.base_api_handler import BaseApiHandler
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
new_task_schema = {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {"type": "string"},
|
||||
"enabled": {
|
||||
"type": "boolean",
|
||||
"default": True,
|
||||
},
|
||||
"action": {
|
||||
"type": "string",
|
||||
},
|
||||
"interval": {"type": "integer"},
|
||||
"interval_type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
# Basic tasks
|
||||
"hours",
|
||||
"minutes",
|
||||
"days",
|
||||
# Chain reaction tasks:
|
||||
"reaction",
|
||||
# CRON tasks:
|
||||
"",
|
||||
],
|
||||
},
|
||||
"start_time": {"type": "string", "pattern": r"\d{1,2}:\d{1,2}"},
|
||||
"command": {"type": ["string", "null"]},
|
||||
"one_time": {"type": "boolean", "default": False},
|
||||
"cron_string": {"type": "string", "default": ""},
|
||||
"parent": {"type": ["integer", "null"]},
|
||||
"delay": {"type": "integer", "default": 0},
|
||||
},
|
||||
"additionalProperties": False,
|
||||
"minProperties": 1,
|
||||
}
|
||||
|
||||
|
||||
class ApiServersServerTasksIndexHandler(BaseApiHandler):
|
||||
def get(self, server_id: str, task_id: str):
|
||||
pass
|
||||
|
||||
def post(self, server_id: str, task_id: str):
|
||||
pass
|
||||
def post(self, server_id: str):
|
||||
auth_data = self.authenticate_user()
|
||||
if not auth_data:
|
||||
return
|
||||
|
||||
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, new_task_schema)
|
||||
except ValidationError as e:
|
||||
return self.finish_json(
|
||||
400,
|
||||
{
|
||||
"status": "error",
|
||||
"error": "INVALID_JSON_SCHEMA",
|
||||
"error_data": str(e),
|
||||
},
|
||||
)
|
||||
|
||||
if server_id not in [str(x["server_id"]) for x in auth_data[0]]:
|
||||
# if the user doesn't have access to the server, return an error
|
||||
return self.finish_json(400, {"status": "error", "error": "NOT_AUTHORIZED"})
|
||||
|
||||
if (
|
||||
EnumPermissionsServer.SCHEDULE
|
||||
not in self.controller.server_perms.get_user_id_permissions_list(
|
||||
auth_data[4]["user_id"], server_id
|
||||
)
|
||||
):
|
||||
# if the user doesn't have Schedule permission, return an error
|
||||
return self.finish_json(400, {"status": "error", "error": "NOT_AUTHORIZED"})
|
||||
data["server_id"] = server_id
|
||||
if not data.get("start_time"):
|
||||
data["start_time"] = "00:00"
|
||||
|
||||
# validate cron string
|
||||
if "cron_string" in data:
|
||||
if data["cron_string"] != "" and not croniter.is_valid(data["cron_string"]):
|
||||
return self.finish_json(
|
||||
405,
|
||||
{
|
||||
"status": "error",
|
||||
"error": self.helper.translation.translate(
|
||||
"error",
|
||||
"cronFormat",
|
||||
self.controller.users.get_user_lang_by_id(
|
||||
auth_data[4]["user_id"]
|
||||
),
|
||||
),
|
||||
},
|
||||
)
|
||||
if "parent" not in data:
|
||||
data["parent"] = None
|
||||
task_id = self.tasks_manager.schedule_job(data)
|
||||
|
||||
self.controller.management.add_to_audit_log(
|
||||
auth_data[4]["user_id"],
|
||||
f"Edited server {server_id}: added schedule",
|
||||
server_id,
|
||||
self.get_remote_ip(),
|
||||
)
|
||||
self.tasks_manager.reload_schedule_from_db()
|
||||
|
||||
self.finish_json(200, {"status": "ok", "data": {"schedule_id": task_id}})
|
||||
|
@ -3,6 +3,7 @@
|
||||
import json
|
||||
import logging
|
||||
|
||||
from croniter import croniter
|
||||
from jsonschema import ValidationError, validate
|
||||
from app.classes.models.server_permissions import EnumPermissionsServer
|
||||
|
||||
@ -35,6 +36,7 @@ task_patch_schema = {
|
||||
"",
|
||||
],
|
||||
},
|
||||
"name": {"type": "string"},
|
||||
"start_time": {"type": "string", "pattern": r"\d{1,2}:\d{1,2}"},
|
||||
"command": {"type": ["string", "null"]},
|
||||
"one_time": {"type": "boolean", "default": False},
|
||||
@ -49,10 +51,47 @@ task_patch_schema = {
|
||||
|
||||
class ApiServersServerTasksTaskIndexHandler(BaseApiHandler):
|
||||
def get(self, server_id: str, task_id: str):
|
||||
pass
|
||||
auth_data = self.authenticate_user()
|
||||
if not auth_data:
|
||||
return
|
||||
if (
|
||||
EnumPermissionsServer.SCHEDULE
|
||||
not in self.controller.server_perms.get_user_id_permissions_list(
|
||||
auth_data[4]["user_id"], server_id
|
||||
)
|
||||
):
|
||||
# if the user doesn't have Schedule permission, return an error
|
||||
return self.finish_json(400, {"status": "error", "error": "NOT_AUTHORIZED"})
|
||||
self.finish_json(200, self.controller.management.get_scheduled_task(task_id))
|
||||
|
||||
def delete(self, server_id: str, task_id: str):
|
||||
pass
|
||||
auth_data = self.authenticate_user()
|
||||
if not auth_data:
|
||||
return
|
||||
if (
|
||||
EnumPermissionsServer.SCHEDULE
|
||||
not in self.controller.server_perms.get_user_id_permissions_list(
|
||||
auth_data[4]["user_id"], server_id
|
||||
)
|
||||
):
|
||||
# if the user doesn't have Schedule permission, return an error
|
||||
return self.finish_json(400, {"status": "error", "error": "NOT_AUTHORIZED"})
|
||||
|
||||
try:
|
||||
self.tasks_manager.remove_job(task_id)
|
||||
except Exception:
|
||||
return self.finish_json(
|
||||
400, {"status": "error", "error": "NO SCHEDULE FOUND"}
|
||||
)
|
||||
self.controller.management.add_to_audit_log(
|
||||
auth_data[4]["user_id"],
|
||||
f"Edited server {server_id}: removed schedule",
|
||||
server_id,
|
||||
self.get_remote_ip(),
|
||||
)
|
||||
self.tasks_manager.reload_schedule_from_db()
|
||||
|
||||
return self.finish_json(200, {"status": "ok"})
|
||||
|
||||
def patch(self, server_id: str, task_id: str):
|
||||
auth_data = self.authenticate_user()
|
||||
@ -96,6 +135,22 @@ class ApiServersServerTasksTaskIndexHandler(BaseApiHandler):
|
||||
if str(data.get("parent")) == str(task_id) and data.get("parent") is not None:
|
||||
data["parent"] = None
|
||||
|
||||
data["server_id"] = server_id
|
||||
if "cron_string" in data:
|
||||
if data["cron_string"] != "" and not croniter.is_valid(data["cron_string"]):
|
||||
return self.finish_json(
|
||||
405,
|
||||
{
|
||||
"status": "error",
|
||||
"error": self.helper.translation.translate(
|
||||
"error",
|
||||
"cronFormat",
|
||||
self.controller.users.get_user_lang_by_id(
|
||||
auth_data[4]["user_id"]
|
||||
),
|
||||
),
|
||||
},
|
||||
)
|
||||
self.tasks_manager.update_job(task_id, data)
|
||||
|
||||
self.controller.management.add_to_audit_log(
|
||||
|
@ -145,7 +145,11 @@ class ServerHandler(BaseHandler):
|
||||
"not a server creator or server limit reached"
|
||||
)
|
||||
return
|
||||
|
||||
page_data["server_api"] = False
|
||||
if page_data["online"]:
|
||||
page_data["server_api"] = self.helper.check_address_status(
|
||||
"https://serverjars.com/api/fetchTypes"
|
||||
)
|
||||
page_data["server_types"] = self.controller.server_jars.get_serverjar_data()
|
||||
page_data["js_server_types"] = json.dumps(
|
||||
self.controller.server_jars.get_serverjar_data()
|
||||
@ -164,7 +168,7 @@ class ServerHandler(BaseHandler):
|
||||
"not a server creator or server limit reached"
|
||||
)
|
||||
return
|
||||
|
||||
page_data["server_api"] = True
|
||||
template = "server/bedrock_wizard.html"
|
||||
|
||||
if page == "steam_cmd_step1":
|
||||
@ -350,7 +354,7 @@ class ServerHandler(BaseHandler):
|
||||
|
||||
if import_type == "import_jar":
|
||||
if self.helper.is_subdir(
|
||||
import_server_path, self.controller.project_root
|
||||
self.controller.project_root, import_server_path
|
||||
):
|
||||
self.redirect(
|
||||
"/panel/error?error=Loop Error: The selected path will cause"
|
||||
@ -516,7 +520,7 @@ class ServerHandler(BaseHandler):
|
||||
|
||||
if import_type == "import_jar":
|
||||
if self.helper.is_subdir(
|
||||
import_server_path, self.controller.project_root
|
||||
self.controller.project_root, import_server_path
|
||||
):
|
||||
self.redirect(
|
||||
"/panel/error?error=Loop Error: The selected path will cause"
|
||||
|
@ -11,6 +11,9 @@ except ModuleNotFoundError as e:
|
||||
|
||||
class CustomStaticHandler(tornado.web.StaticFileHandler):
|
||||
def validate_absolute_path(self, root: str, absolute_path: str) -> Optional[str]:
|
||||
# This is for the mobile app service worker
|
||||
if self.request.path.find("service-worker.js") != -1:
|
||||
self.set_header("Service-Worker-Allowed", "/")
|
||||
try:
|
||||
return super().validate_absolute_path(root, absolute_path)
|
||||
except tornado.web.HTTPError as error:
|
||||
|
@ -278,11 +278,11 @@ class UploadHandler(BaseHandler):
|
||||
filename = self.request.headers.get("X-FileName", None)
|
||||
full_path = os.path.join(path, filename)
|
||||
|
||||
if not Helpers.in_path(
|
||||
if not self.helper.is_subdir(
|
||||
full_path,
|
||||
Helpers.get_os_understandable_path(
|
||||
self.controller.servers.get_server_data_by_id(server_id)["path"]
|
||||
),
|
||||
full_path,
|
||||
):
|
||||
logger.warning(
|
||||
f"User {user_id} tried to upload a file to {server_id} "
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"major": 4,
|
||||
"minor": 0,
|
||||
"sub": 23
|
||||
"minor": 1,
|
||||
"sub": 4
|
||||
}
|
||||
|
40
app/frontend/static/assets/crafty.webmanifest
Normal file
40
app/frontend/static/assets/crafty.webmanifest
Normal file
@ -0,0 +1,40 @@
|
||||
{
|
||||
"background_color": "#222436",
|
||||
"description": "Crafty Controller is a free and open-source Minecraft launcher and manager that allows users to start and administer Minecraft servers from a user-friendly interface.",
|
||||
"dir": "ltr",
|
||||
"display": "standalone",
|
||||
"name": "Crafty Controller",
|
||||
"orientation": "any",
|
||||
"scope": "/",
|
||||
"short_name": "Crafty",
|
||||
"start_url": "/",
|
||||
"theme_color": "#222436",
|
||||
"categories": ["utilities"],
|
||||
"icons": [
|
||||
{
|
||||
"src": "/static/assets/images/Crafty_4-0_Logo_square.ico",
|
||||
"type": "image/x-icon",
|
||||
"sizes":"128x128"
|
||||
},
|
||||
{
|
||||
"src": "/static/assets/images/Crafty_4-0.png",
|
||||
"type": "image/png",
|
||||
"sizes": "144x144",
|
||||
"purpose": "any"
|
||||
},
|
||||
{
|
||||
"src": "/static/assets/images/crafty-logo-square-1024.png",
|
||||
"type": "image/png",
|
||||
"sizes": "1024x1024",
|
||||
"purpose": "any"
|
||||
},
|
||||
{
|
||||
"src": "/static/assets/images/crafty-logo-square-96.png",
|
||||
"type": "image/png",
|
||||
"sizes": "96x96",
|
||||
"purpose": "any"
|
||||
}
|
||||
],
|
||||
"lang": "en",
|
||||
"prefer_related_applications": false
|
||||
}
|
@ -135,3 +135,58 @@ body {
|
||||
.accordion .card {
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
.bootbox-body {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/**************************************************************/
|
||||
/* CSS for Froms Displays */
|
||||
/**************************************************************/
|
||||
div>.input-group>.custom-file-input {
|
||||
position: relative !important;
|
||||
-webkit-box-flex: 1 !important;
|
||||
-ms-flex: 1 1 auto !important;
|
||||
flex: 1 1 auto !important;
|
||||
width: 1% !important;
|
||||
margin-bottom: 0 !important;
|
||||
border: 1px solid var(--outline);
|
||||
}
|
||||
|
||||
div>.input-group>.form-control-file {
|
||||
position: relative !important;
|
||||
-webkit-box-flex: 1 !important;
|
||||
-ms-flex: 1 1 auto !important;
|
||||
flex: 1 1 auto !important;
|
||||
width: 1% !important;
|
||||
margin-bottom: 0 !important;
|
||||
border: 1px solid var(--outline);
|
||||
}
|
||||
|
||||
.custom-picker {
|
||||
border: 1px solid var(--outline);
|
||||
}
|
||||
|
||||
div>.input-group>.form-control {
|
||||
position: relative !important;
|
||||
-webkit-box-flex: 1 !important;
|
||||
-ms-flex: 1 1 auto !important;
|
||||
flex: 1 1 auto !important;
|
||||
width: 1% !important;
|
||||
margin-bottom: 0 !important;
|
||||
border: 1px solid var(--outline);
|
||||
}
|
||||
|
||||
.input-group>.input-group-append>button.upload-button {
|
||||
height: calc(1.5em + 0.75rem + 2px);
|
||||
}
|
||||
|
||||
.no-scroll {
|
||||
-ms-overflow-style: none; /* IE and Edge */
|
||||
scrollbar-width: none; /* Firefox */
|
||||
}
|
||||
|
||||
.no-scroll::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
/**************************************************************/
|
BIN
app/frontend/static/assets/images/Crafty_4-0.png
Normal file
BIN
app/frontend/static/assets/images/Crafty_4-0.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.9 KiB |
BIN
app/frontend/static/assets/images/crafty-logo-square-1024.png
Normal file
BIN
app/frontend/static/assets/images/crafty-logo-square-1024.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 424 KiB |
BIN
app/frontend/static/assets/images/crafty-logo-square-96.png
Normal file
BIN
app/frontend/static/assets/images/crafty-logo-square-96.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.8 KiB |
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 17 KiB |
120
app/frontend/static/assets/images/serverjars/FULL-WHITE.svg
Normal file
120
app/frontend/static/assets/images/serverjars/FULL-WHITE.svg
Normal file
@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 26.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 683.6 143.8" style="enable-background:new 0 0 683.6 143.8;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{opacity:0.85;fill:#FFFFFF;enable-background:new ;}
|
||||
.st1{opacity:0.85;}
|
||||
.st2{fill:#FFFFFF;}
|
||||
.st3{fill:none;}
|
||||
.st4{fill:url(#SVGID_1_);}
|
||||
.st5{fill:url(#SVGID_00000137122815686618769650000009047437546445953421_);}
|
||||
.st6{fill:url(#SVGID_00000170963539203169094570000007184871682409824703_);}
|
||||
.st7{fill:url(#SVGID_00000169549353698428389090000007910489870824235905_);}
|
||||
.st8{fill-rule:evenodd;clip-rule:evenodd;fill:url(#SVGID_00000029754379306852418700000008865188217784465572_);}
|
||||
</style>
|
||||
<path class="st0" d="M175.8,111.5h17.6v3.8h-13.2v8.9h12.1v3.7h-12.1v11.8h-4.4V111.5z"/>
|
||||
<path class="st0" d="M196.3,119.1h4.2v3.5h0.1c0.4-2.3,2.4-3.9,4.7-3.9c0.5,0,1,0.1,1.5,0.2v3.9c-0.6-0.2-1.3-0.3-1.9-0.2
|
||||
c-2.7,0-4.4,1.8-4.4,4.8v12.3h-4.2L196.3,119.1z"/>
|
||||
<path class="st0" d="M207.2,129.4L207.2,129.4c0-6.6,3.9-10.6,9.7-10.6s9.8,4,9.8,10.6l0,0c0,6.6-3.9,10.7-9.8,10.7
|
||||
S207.2,136,207.2,129.4z M222.4,129.4L222.4,129.4c0-4.5-2.2-7.1-5.5-7.1s-5.4,2.6-5.4,7.1l0,0c0,4.5,2.2,7.2,5.5,7.2
|
||||
S222.4,133.9,222.4,129.4L222.4,129.4z"/>
|
||||
<path class="st0" d="M229.6,119.1h4.2v3.2h0.1c1-2.3,3.2-3.7,5.7-3.6c2.6-0.2,5,1.5,5.7,4h0.1c1.1-2.5,3.6-4.1,6.4-4
|
||||
c4.1,0,6.7,2.7,6.7,6.8v14.1h-4.2v-13.1c0-2.7-1.4-4.2-3.9-4.2c-2.3,0-4.2,1.8-4.3,4.2c0,0.1,0,0.2,0,0.3v12.9H242v-13.4
|
||||
c0.2-2-1.3-3.8-3.3-3.9c-0.2,0-0.4,0-0.5,0c-2.4,0-4.3,2-4.3,4.3c0,0.1,0,0.2,0,0.3v12.7h-4.2L229.6,119.1z"/>
|
||||
<g id="Layer_2_00000138553854520646606810000012156271018779627156_" class="st1">
|
||||
<g id="Layer_1-2">
|
||||
<path class="st2" d="M343.7,139.9c-6.9,0-12.5-5.6-12.5-12.5s5.6-12.5,12.5-12.5c2.1,0,4.2,0.5,6,1.5c1.8,1,3.3,2.4,4.3,4.1
|
||||
l-4.1,2.4c-0.6-1.1-1.5-1.9-2.5-2.5c-3.1-1.6-6.8-1.1-9.4,1.3c-1.5,1.5-2.2,3.6-2.1,5.7c-0.1,2.1,0.7,4.1,2.1,5.7
|
||||
c1.5,1.5,3.5,2.3,5.7,2.2c1.3,0,2.6-0.3,3.7-0.9c1.1-0.6,2-1.4,2.5-2.5l4.1,2.4c-1,1.7-2.5,3.2-4.3,4.1
|
||||
C347.8,139.4,345.8,139.9,343.7,139.9z"/>
|
||||
<path class="st2" d="M361.4,122.3v3c0.3-1,1.1-1.9,2-2.5c1-0.6,2.1-0.9,3.2-0.8v4.9c-1.3-0.2-2.6,0.1-3.6,0.8
|
||||
c-1.1,0.8-1.7,2.2-1.6,3.5v8.2H357v-17.2H361.4z"/>
|
||||
<path class="st2" d="M381.6,124.3v-2h4.4v17.2h-4.4v-2c-1.4,1.7-3.4,2.6-5.6,2.5c-2.2,0-4.4-0.9-5.9-2.6c-1.6-1.8-2.5-4.1-2.4-6.5
|
||||
c-0.1-2.4,0.8-4.7,2.4-6.4c1.5-1.7,3.6-2.7,5.9-2.7C378.1,121.7,380.2,122.6,381.6,124.3z M373.4,134.3c1.9,1.8,4.9,1.8,6.8,0
|
||||
c0.9-0.9,1.4-2.2,1.4-3.5c0.1-1.3-0.4-2.6-1.4-3.5c-1.9-1.8-4.9-1.8-6.8,0c-0.9,0.9-1.4,2.2-1.3,3.5
|
||||
C372,132.1,372.5,133.4,373.4,134.3z"/>
|
||||
<path class="st2" d="M399.2,115v4.2c-2.4-0.2-3.6,0.8-3.7,2.9v0.2h3.6v4.3h-3.6v12.9h-4.4v-12.9h-2.5v-4.2h2.5v-0.2
|
||||
c-0.2-2,0.6-4.1,2-5.5C394.5,115.3,396.6,114.8,399.2,115z"/>
|
||||
<path class="st2" d="M411.6,122.3v4.2h-3.9v7.1c0,0.5,0.1,1,0.5,1.3c0.4,0.3,0.8,0.5,1.3,0.5c0.7,0,1.4,0,2.1,0v4
|
||||
c-3,0.3-5.1,0.1-6.4-0.8s-1.9-2.5-1.9-4.9v-7.1h-3v-4.2h3v-3.5l4.4-1.3v4.8L411.6,122.3z"/>
|
||||
<path class="st2" d="M427.2,124.3v-2h4.4v17.2h-4.4v-2c-1.4,1.7-3.4,2.6-5.6,2.5c-2.2,0-4.4-0.9-5.9-2.6c-1.6-1.8-2.5-4.1-2.4-6.5
|
||||
c-0.1-2.4,0.8-4.7,2.4-6.4c1.5-1.7,3.6-2.7,5.9-2.7C423.8,121.7,425.9,122.6,427.2,124.3z M419.1,134.3c1.9,1.8,4.9,1.8,6.8,0
|
||||
c0.9-0.9,1.4-2.2,1.4-3.5c0-1.3-0.4-2.5-1.4-3.5c-1.9-1.8-4.9-1.8-6.8,0c-0.9,0.9-1.4,2.2-1.3,3.5
|
||||
C417.7,132.1,418.2,133.4,419.1,134.3L419.1,134.3z"/>
|
||||
<path class="st2" d="M440.1,122.3v3c0.4-1,1.1-1.9,2-2.5c1-0.6,2.1-0.9,3.2-0.8v4.9c-1.3-0.2-2.6,0.1-3.6,0.8
|
||||
c-1.1,0.8-1.7,2.2-1.6,3.5v8.2h-4.4v-17.2H440.1z"/>
|
||||
<path class="st2" d="M461.9,137.3c-3.6,3.6-9.3,3.6-12.9,0s-3.6-9.3,0-12.9l0,0c3.6-3.5,9.3-3.5,12.9,0.1c1.7,1.7,2.6,4,2.6,6.4
|
||||
C464.5,133.3,463.6,135.6,461.9,137.3z M452.1,134.3c1.9,1.8,4.8,1.8,6.7,0c1.8-1.9,1.8-4.9,0-6.8c-1.9-1.8-4.8-1.8-6.7,0
|
||||
C450.3,129.4,450.3,132.3,452.1,134.3L452.1,134.3z"/>
|
||||
<path class="st2" d="M320,137.6l-2.9-20.3c-0.4-2.7-2.7-4.7-5.5-4.7h-9c-0.3,0-0.5,0.2-0.7,0.4l-0.9,2H292l-0.9-2
|
||||
c-0.1-0.3-0.4-0.4-0.7-0.4h-9c-2.7,0-5.1,2-5.5,4.7l-2.9,20.3c-0.4,3,1.7,5.8,4.7,6.2c0,0,0,0,0,0l0,0c0.3,0,0.5,0.1,0.8,0.1h36
|
||||
c3,0,5.5-2.5,5.5-5.5l0,0C320,138.1,320,137.8,320,137.6z M287.1,130c-2.7,0-4.9-2.2-4.9-4.9c0-2.7,2.2-4.9,4.9-4.9
|
||||
c2.7,0,4.9,2.2,4.9,4.9c0,0,0,0,0,0l0,0C292,127.8,289.8,130,287.1,130z M296.5,138c-2.7,0-4.9-2.2-4.9-4.9h9.8
|
||||
C301.4,135.8,299.3,138,296.5,138L296.5,138L296.5,138z M305.9,130c-2.7,0-4.9-2.2-4.9-4.9c0-2.7,2.2-4.9,4.9-4.9
|
||||
c2.7,0,4.9,2.2,4.9,4.9c0,0,0,0,0,0l0,0C310.8,127.8,308.6,130,305.9,130L305.9,130z"/>
|
||||
</g>
|
||||
</g>
|
||||
<path class="st2" d="M133.1,19.2H9.7c-1.8,0-3.2-1.4-3.2-3.2V3.2C6.5,1.5,7.9,0,9.7,0h123.4c1.8,0,3.2,1.4,3.2,3.2V16
|
||||
C136.3,17.8,134.9,19.2,133.1,19.2"/>
|
||||
<path class="st2" d="M23.6,36.7c-3.4,0-6.7,1.6-8.8,4.3c-2.9,3.6-4.1,8.3-3.2,12.8l9.2,51.9c1.2,6.6,6.2,11.4,12.1,11.4H110
|
||||
c5.8,0,10.9-4.8,12.1-11.4l9.2-51.9c0.8-4.5-0.4-9.2-3.3-12.8c-2.1-2.7-5.4-4.3-8.8-4.3H23.6z M110,128.3H32.8
|
||||
c-11.3,0-21-8.7-23.1-20.7L0.5,55.8c-1.5-7.8,0.6-15.9,5.7-22c4.3-5.2,10.7-8.3,17.4-8.3h95.6c6.8,0.1,13.1,3.1,17.4,8.3
|
||||
c5.1,6.1,7.2,14.2,5.7,22l-9.2,51.9C130.9,119.7,121.2,128.4,110,128.3"/>
|
||||
<path class="st2" d="M120.8,23.8v-2.2c2,0,3.5-1.6,3.5-3.6c0-1.8-1.5-3.4-3.3-3.5H21.6c-2,0.1-3.5,1.8-3.4,3.7
|
||||
c0.1,1.8,1.5,3.3,3.4,3.4v2.2c-3.2-0.1-5.7-2.8-5.6-6c0.1-3,2.5-5.4,5.6-5.6h99.2c3.2-0.1,5.9,2.4,6,5.6s-2.4,5.9-5.6,6
|
||||
C121.1,23.8,121,23.8,120.8,23.8"/>
|
||||
<path class="st2" d="M120.8,33.1H21.6c-3.2,0-5.8-2.6-5.8-5.8c0-3.2,2.6-5.8,5.8-5.8v2.2c-2,0.1-3.5,1.8-3.4,3.7
|
||||
c0.1,1.8,1.5,3.3,3.4,3.4h99.2c2,0.1,3.7-1.3,3.8-3.3c0.1-2-1.3-3.7-3.3-3.8c-0.1,0-0.2,0-0.3,0h-0.2v-2.2c3.2-0.1,5.9,2.4,6,5.6
|
||||
s-2.4,5.9-5.6,6C121.1,33.1,121,33.1,120.8,33.1"/>
|
||||
<path class="st2" d="M21.6,21.5l36.1,1.1l-36.1,1.1V21.5z"/>
|
||||
<path class="st2" d="M125.5,23.8l-45.1-1.1l45.1-1.1V23.8z"/>
|
||||
<rect x="-2.5" y="-1.1" class="st3" width="571.3" height="131.4"/>
|
||||
<path class="st2" d="M163.8,91.7l7.3-10.9c5.8,5.5,14.3,9.3,22.3,9.3c7.1,0,13.1-3.3,13.1-8.3c0-6-8.1-7.9-15.4-9.6
|
||||
c-13.7-3.2-24.8-9.8-24.8-22.3c0-12.7,11.1-21,27.1-21c10.7,0,19.4,3.7,24.7,8.9l-6.6,10.8c-4-3.9-11.2-6.9-18.3-6.9
|
||||
s-12.2,3.2-12.2,7.7c0,5.5,7.4,7.9,14.1,9.3s26.2,6.2,26.2,22.5c0,12.8-12.2,21.6-27.8,21.6C182.6,102.8,171.1,98.4,163.8,91.7z"/>
|
||||
<path class="st2" d="M281.7,80.1h-40.9c1.9,6.6,7.5,10.9,15.1,10.9c5.6,0.1,10.9-2.3,14.5-6.5l9,7.9c-5.5,6.5-14,10.5-23.9,10.5
|
||||
c-16.8,0-29.3-12-29.3-27.8c0-15.6,12.1-27.4,28-27.4S282,59.4,282,75.3C282,76.9,281.9,78.5,281.7,80.1z M240.8,70.3h26.9
|
||||
c-1.7-6.6-6.9-10.9-13.4-10.9C247.7,59.4,242.5,63.8,240.8,70.3L240.8,70.3z"/>
|
||||
<path class="st2" d="M321.3,48v13.9h-2.3c-9.6,0-15.2,5.7-15.2,14.7v25h-13.4V48.9h13.5v6.8c3.6-4.8,9.2-7.7,15.2-7.7L321.3,48z"/>
|
||||
<path class="st2" d="M381.9,48.9L360,101.6h-13.9l-21.9-52.8h15.3l13.8,35.9L367,48.9H381.9z"/>
|
||||
<path class="st2" d="M437.1,80.1h-40.9c1.9,6.6,7.5,10.9,15.1,10.9c5.6,0.1,10.9-2.3,14.5-6.5l9,7.9c-5.5,6.5-14,10.5-23.9,10.5
|
||||
c-16.8,0-29.3-12-29.3-27.8c0-15.6,12.1-27.4,28-27.4s27.7,11.8,27.7,27.7C437.4,76.9,437.3,78.5,437.1,80.1z M396.1,70.3H423
|
||||
c-1.7-6.6-6.9-10.9-13.4-10.9S397.7,63.8,396.1,70.3L396.1,70.3z"/>
|
||||
<path class="st2" d="M476.7,48v13.9h-2.2c-9.6,0-15.2,5.7-15.2,14.7v25h-13.5V48.9h13.5v6.8c3.6-4.8,9.2-7.7,15.2-7.7L476.7,48z"/>
|
||||
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="870.0443" y1="434.2369" x2="907.1767" y2="465.2789" gradientTransform="matrix(1 0 0 1 -374.6 -381.3801)">
|
||||
<stop offset="0" style="stop-color:#FEAF6F"/>
|
||||
<stop offset="1" style="stop-color:#FD5E83"/>
|
||||
</linearGradient>
|
||||
<path class="st4" d="M492.5,100.6V87c3.2,1.4,6.6,2.1,10,2.2c7.3,0,11.8-3.9,11.8-10.9v-48h14.3V79c0,15-9.8,23.9-24.5,23.9
|
||||
C500,102.9,496.1,102.1,492.5,100.6z"/>
|
||||
<linearGradient id="SVGID_00000162328622213414588160000008200821717462734513_" gradientUnits="userSpaceOnUse" x1="920.7661" y1="434.5518" x2="972.3098" y2="477.6348" gradientTransform="matrix(1 0 0 1 -374.6 -381.3801)">
|
||||
<stop offset="0" style="stop-color:#FEAF6F"/>
|
||||
<stop offset="1" style="stop-color:#FD5E83"/>
|
||||
</linearGradient>
|
||||
<path style="fill:url(#SVGID_00000162328622213414588160000008200821717462734513_);" d="M593.2,48.9v52.8h-13.5v-6.3
|
||||
c-4.4,4.9-10.6,7.6-17.2,7.5c-14.7,0-25.8-11.9-25.8-27.6s11.1-27.6,25.8-27.6c6.5-0.1,12.8,2.7,17.2,7.5v-6.3L593.2,48.9z
|
||||
M579.8,75.2c0-8-6.6-14.5-14.6-14.5c-8,0-14.5,6.6-14.5,14.6c0,8,6.5,14.4,14.5,14.5c7.9,0.2,14.4-6,14.6-13.9
|
||||
C579.8,75.7,579.8,75.5,579.8,75.2z"/>
|
||||
<linearGradient id="SVGID_00000026849485640012965730000014957007722205225107_" gradientUnits="userSpaceOnUse" x1="973.2171" y1="437.9167" x2="1007.0711" y2="466.2133" gradientTransform="matrix(1 0 0 1 -374.6 -381.3801)">
|
||||
<stop offset="0" style="stop-color:#FEAF6F"/>
|
||||
<stop offset="1" style="stop-color:#FD5E83"/>
|
||||
</linearGradient>
|
||||
<path style="fill:url(#SVGID_00000026849485640012965730000014957007722205225107_);" d="M635.9,48v13.9h-2.3
|
||||
c-9.6,0-15.2,5.7-15.2,14.7v25H605V48.9h13.4v6.8c3.6-4.8,9.2-7.7,15.2-7.7L635.9,48z"/>
|
||||
<linearGradient id="SVGID_00000011000279650532451330000005619277557075874698_" gradientUnits="userSpaceOnUse" x1="1015.3561" y1="439.477" x2="1056.9301" y2="474.2302" gradientTransform="matrix(1 0 0 1 -374.6 -381.3801)">
|
||||
<stop offset="0" style="stop-color:#FEAF6F"/>
|
||||
<stop offset="1" style="stop-color:#FD5E83"/>
|
||||
</linearGradient>
|
||||
<path style="fill:url(#SVGID_00000011000279650532451330000005619277557075874698_);" d="M638.7,94.8l6.5-8.9
|
||||
c4.2,3.8,9.7,5.9,15.4,5.9c5.4,0,9.3-1.8,9.3-5c0-3.5-4.6-4.8-10.3-6.1c-8.4-1.9-19.2-4.5-19.2-16.5c0-11.2,9.8-16.7,21.5-16.7
|
||||
c7.4-0.1,14.6,2.3,20.5,6.9l-6.5,9c-3.9-3.1-8.7-4.8-13.7-4.9c-4.6,0-8.3,1.5-8.3,4.5c0,3.5,4.4,4.7,10.3,5.9
|
||||
c8.4,1.9,19.2,4.5,19.2,16.4c0,11.2-9.9,17.3-22.6,17.3C652.9,102.9,644.9,100.1,638.7,94.8z"/>
|
||||
<linearGradient id="SVGID_00000176732902084481618460000012775063734620060048_" gradientUnits="userSpaceOnUse" x1="408.7259" y1="431.5905" x2="485.4144" y2="495.6844" gradientTransform="matrix(1 0 0 1 -374.6 -381.3801)">
|
||||
<stop offset="0" style="stop-color:#FEAF6F"/>
|
||||
<stop offset="1" style="stop-color:#FD5E83"/>
|
||||
</linearGradient>
|
||||
<path style="fill-rule:evenodd;clip-rule:evenodd;fill:url(#SVGID_00000176732902084481618460000012775063734620060048_);" d="
|
||||
M124.5,62c-12.7,0.9-27,5.5-35.7,12.3c-38.7,30.3-69.2-6.6-69.3-6.6l6.8,36.8c0.8,4.3,4.6,7.5,9,7.5l73,0.2c4.5,0,8.3-3.2,9.1-7.6
|
||||
L124.5,62z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 10 KiB |
1
app/frontend/static/assets/images/serverjars/ICON.svg
Normal file
1
app/frontend/static/assets/images/serverjars/ICON.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 142.71 128.36"><defs><style>.cls-1{fill:#fff;}.cls-2{fill-rule:evenodd;fill:url(#linear-gradient);}</style><linearGradient id="linear-gradient" x1="408.73" y1="431.59" x2="485.41" y2="495.68" gradientTransform="translate(-374.6 -381.38)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#feaf6f"/><stop offset="1" stop-color="#fd5e83"/></linearGradient></defs><path class="cls-1" d="M133.09,19.17H9.67A3.24,3.24,0,0,1,6.46,16V3.24A3.24,3.24,0,0,1,9.7,0H133.09a3.25,3.25,0,0,1,3.25,3.24V16a3.25,3.25,0,0,1-3.25,3.24"/><path class="cls-1" d="M23.61,36.67A11.41,11.41,0,0,0,14.8,41a15.79,15.79,0,0,0-3.25,12.8l9.18,51.92c1.17,6.62,6.25,11.42,12.06,11.42H110c5.82,0,10.89-4.8,12.06-11.42l9.18-51.91A15.86,15.86,0,0,0,128,41a11.5,11.5,0,0,0-8.82-4.33ZM110,128.35H32.8c-11.27,0-21-8.7-23.12-20.69L.46,55.75a26.72,26.72,0,0,1,5.71-22,22.77,22.77,0,0,1,17.41-8.34h95.56a22.8,22.8,0,0,1,17.41,8.34,26.79,26.79,0,0,1,5.71,22l-9.19,51.91c-2.12,12-11.84,20.7-23.12,20.7"/><path class="cls-1" d="M120.8,23.76V21.51A3.56,3.56,0,0,0,121,14.4H21.59a3.56,3.56,0,0,0,0,7.11v2.25a5.81,5.81,0,0,1,0-11.61H120.8a5.81,5.81,0,0,1,.48,11.61h-.48"/><path class="cls-1" d="M120.8,33.11H21.59a5.8,5.8,0,0,1,0-11.6v2.24a3.56,3.56,0,0,0,0,7.11H120.8a3.56,3.56,0,0,0,.52-7.1h-.52V21.51a5.81,5.81,0,0,1,.48,11.61,3.84,3.84,0,0,1-.48,0"/><path class="cls-1" d="M21.59,21.51l36.13,1.13L21.59,23.76Z"/><path class="cls-1" d="M125.46,23.76,80.35,22.64l45.11-1.13Z"/><path class="cls-2" d="M124.46,62c-12.72.93-27,5.55-35.7,12.34-38.69,30.34-69.25-6.6-69.28-6.58l6.75,36.83a9.16,9.16,0,0,0,9,7.52l73,.16a9.17,9.17,0,0,0,9.06-7.64Z"/></svg>
|
After Width: | Height: | Size: 1.7 KiB |
46
app/frontend/static/assets/js/shared/service-worker.js
Normal file
46
app/frontend/static/assets/js/shared/service-worker.js
Normal file
@ -0,0 +1,46 @@
|
||||
// This is the "Offline page" service worker
|
||||
|
||||
importScripts('https://storage.googleapis.com/workbox-cdn/releases/5.1.2/workbox-sw.js');
|
||||
|
||||
const CACHE = "crafty-controller";
|
||||
|
||||
// TODO: replace the following with the correct offline fallback page i.e.: const offlineFallbackPage = "offline.html";
|
||||
const offlineFallbackPage = "/offline";
|
||||
|
||||
self.addEventListener("message", (event) => {
|
||||
if (event.data && event.data.type === "SKIP_WAITING") {
|
||||
self.skipWaiting();
|
||||
}
|
||||
});
|
||||
|
||||
self.addEventListener('install', async (event) => {
|
||||
event.waitUntil(
|
||||
caches.open(CACHE)
|
||||
.then((cache) => cache.add(offlineFallbackPage))
|
||||
);
|
||||
});
|
||||
|
||||
if (workbox.navigationPreload.isSupported()) {
|
||||
workbox.navigationPreload.enable();
|
||||
}
|
||||
|
||||
self.addEventListener('fetch', (event) => {
|
||||
if (event.request.mode === 'navigate') {
|
||||
event.respondWith((async () => {
|
||||
try {
|
||||
const preloadResp = await event.preloadResponse;
|
||||
|
||||
if (preloadResp) {
|
||||
return preloadResp;
|
||||
}
|
||||
const networkResp = await fetch(event.request);
|
||||
return networkResp;
|
||||
} catch (error) {
|
||||
|
||||
const cache = await caches.open(CACHE);
|
||||
const cachedResp = await cache.match(offlineFallbackPage);
|
||||
return cachedResp;
|
||||
}
|
||||
})());
|
||||
}
|
||||
});
|
@ -19,6 +19,16 @@
|
||||
<link rel="stylesheet" href="/static/assets/vendors/css/vendor.bundle.base.css">
|
||||
<link rel="stylesheet" href="/static/assets/css/crafty.css">
|
||||
|
||||
<link rel="manifest" href="/static/assets/crafty.webmanifest">
|
||||
<meta name="mobile-web-app-capable" content="yes">
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<meta name="mobile-web-app-capable" content="yes" />
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black">
|
||||
<meta name="apple-mobile-web-app-title" content="Crafty">
|
||||
<link rel="apple-touch-icon" href="../static/assets/images/Crafty_4-0.png">
|
||||
<link rel="shortcut icon" sizes="192x192" href="../static/assets/images/Crafty_4-0.png">
|
||||
|
||||
|
||||
<!-- endinject -->
|
||||
|
||||
<!-- Plugin css for this page-->
|
||||
@ -247,7 +257,7 @@
|
||||
|
||||
const sendWssError = () => wsOpen || warn(
|
||||
'WebSockets are required for Crafty to work. This websocket connection has been closed. Are you using a reverse proxy?',
|
||||
'https://wiki.craftycontrol.com/en/4/docs/Reverse%20Proxy%20Examples',
|
||||
'https://docs.craftycontrol.com/pages/getting-started/proxies/',
|
||||
'wssError'
|
||||
)
|
||||
|
||||
@ -526,6 +536,14 @@
|
||||
|
||||
});
|
||||
});
|
||||
$(document).ready(() => {
|
||||
if ('serviceWorker' in navigator) {
|
||||
navigator.serviceWorker.register('/static/assets/js/shared/service-worker.js', {scope: '/'})
|
||||
.then(function (registration) {
|
||||
console.log('Service Worker Registered');
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
{% block js %}
|
||||
|
@ -14,6 +14,13 @@
|
||||
<link rel="stylesheet" href="/static/assets/vendors/css/vendor.bundle.base.css">
|
||||
<link rel="stylesheet" href="/static/assets/vendors/fontawesome6/css/all.css">
|
||||
<link rel="stylesheet" href="/static/assest/css/crafty.css">
|
||||
<link rel="manifest" href="/static/assets/crafty.webmanifest">
|
||||
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<meta name="mobile-web-app-capable" content="yes" />
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black">
|
||||
<meta name="apple-mobile-web-app-title" content="Crafty">
|
||||
<link rel="apple-touch-icon" href="../static/assets/images/Crafty_4-0.png">
|
||||
<!-- endinject -->
|
||||
<!-- Plugin css for this page -->
|
||||
<!-- End Plugin css for this page -->
|
||||
|
@ -100,7 +100,7 @@
|
||||
</li>
|
||||
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="https://wiki.craftycontrol.com" target="_blank">
|
||||
<a class="nav-link" href="https://docs.craftycontrol.com" target="_blank">
|
||||
<i class="fas fa-book"></i>
|
||||
<span class="menu-title">{{ translate('sidebar', 'documentation', data['lang']) }}</span>
|
||||
</a>
|
||||
@ -109,7 +109,7 @@
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/panel/wiki">
|
||||
<i class="fa fa-info-circle"></i>
|
||||
<span class="menu-title">Wiki</span>
|
||||
<span class="menu-title">{{ translate('sidebar', 'inApp', data['lang']) }}</span>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
|
@ -6,8 +6,7 @@
|
||||
{% block title %}Crafty Controller - {{ translate('panelConfig', 'pageTitle', data['lang']) }}{% end %}
|
||||
|
||||
{% block content %}
|
||||
<link rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-select/1.13.10/css/bootstrap-select.min.css">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-select/1.13.10/css/bootstrap-select.min.css">
|
||||
|
||||
|
||||
<div class="content-wrapper">
|
||||
@ -30,7 +29,12 @@
|
||||
<div class="card-body">
|
||||
|
||||
{% if data['superuser'] %}
|
||||
<span class="d-none d-sm-block">
|
||||
{% include "parts/crafty_config_list.html %}
|
||||
</span>
|
||||
<span class="d-block d-sm-none">
|
||||
{% include "parts/m_crafty_config_list.html %}
|
||||
</span>
|
||||
{% end %}
|
||||
|
||||
<!-- Page Title Header Starts-->
|
||||
@ -69,11 +73,8 @@
|
||||
</select>
|
||||
{% elif item[0] == 'disabled_language_files' %}
|
||||
<div class="input-group">
|
||||
<button type="button" class="btn btn-outline-default custom-picker" onclick="$('option', $('#lang_select')).each(function(element) {
|
||||
$(this).removeAttr('selected').prop('selected', false); $('.selectpicker').selectpicker('refresh')
|
||||
});">{{ translate('panelConfig', 'enableLang', data['lang']) }}</button>
|
||||
<select id="lang_select" class="form-control selectpicker show-tick" data-icon-base="fas"
|
||||
data-tick-icon="fa-check" multiple data-style="custom-picker">
|
||||
<button type="button" class="btn btn-outline-default custom-picker" onclick="$('option', $('#lang_select')).each(function(element) {$(this).removeAttr('selected').prop('selected', false); $('.selectpicker').selectpicker('refresh')});">{{ translate('panelConfig', 'enableLang', data['lang']) }}</button>
|
||||
<select id="lang_select" class="form-control selectpicker show-tick custom-picker" data-icon-base="fas" data-tick-icon="fa-check" multiple data-style="custom-picker">
|
||||
{% for lang in data['all_languages'] %}
|
||||
{% if lang in item[1] %}
|
||||
<option selected>{{lang}}</option>
|
||||
@ -82,17 +83,12 @@
|
||||
{% end %}
|
||||
{% end %}
|
||||
</select>
|
||||
<textarea id="disabled_lang" name="{{item[0]}}" class="form-control list hidden"
|
||||
rows="{{ len(data['all_languages']) }}" value="{{','.join(item[1])}}"
|
||||
hidden>{{','.join(item[1])}}</textarea>
|
||||
<textarea id="disabled_lang" name="{{item[0]}}" class="form-control list hidden" rows="{{ len(data['all_languages']) }}" value="{{','.join(item[1])}}" hidden>{{','.join(item[1])}}</textarea>
|
||||
</div>
|
||||
{% elif item[0] == 'monitored_mounts'%}
|
||||
<div class="input-group">
|
||||
<button type="button" class="btn btn-outline-default custom-picker" onclick="$('option', $('#mount_select')).each(function(element) {
|
||||
$(this).removeAttr('selected').prop('selected', false); $('.selectpicker').selectpicker('refresh')
|
||||
});">{{ translate('panelConfig', 'noMounts', data['lang']) }}</button>
|
||||
<select id="mount_select" class="form-control selectpicker show-tick" data-icon-base="fas"
|
||||
data-tick-icon="fa-check" multiple data-style="custom-picker">
|
||||
<button type="button" class="btn btn-outline-default custom-picker" onclick="$('option', $('#mount_select')).each(function(element) {$(this).removeAttr('selected').prop('selected', false); $('.selectpicker').selectpicker('refresh')});">{{ translate('panelConfig', 'noMounts', data['lang']) }}</button>
|
||||
<select id="mount_select" class="form-control selectpicker show-tick" data-icon-base="fas" data-tick-icon="fa-check" multiple data-style="custom-picker">
|
||||
{% for mount in data['all_partitions'] %}
|
||||
{% if mount in item[1] %}
|
||||
<option selected>{{mount}}</option>
|
||||
@ -101,13 +97,10 @@
|
||||
{% end %}
|
||||
{% end %}
|
||||
</select>
|
||||
<textarea id="monitored_mounts" name="{{item[0]}}" class="form-control list hidden"
|
||||
rows="{{ len(data['all_partitions']) }}" value="{{','.join(item[1])}}"
|
||||
hidden>{{','.join(item[1])}}</textarea>
|
||||
<textarea id="monitored_mounts" name="{{item[0]}}" class="form-control list hidden" rows="{{ len(data['all_partitions']) }}" value="{{','.join(item[1])}}" hidden>{{','.join(item[1])}}</textarea>
|
||||
</div>
|
||||
{% elif isinstance(item[1], list) %}
|
||||
<textarea value="{{','.join(item[1])}}" type="text" name="{{item[0]}}"
|
||||
class="form-control list">{{','.join(item[1])}}</textarea>
|
||||
<textarea value="{{','.join(item[1])}}" type="text" name="{{item[0]}}" class="form-control list">{{','.join(item[1])}}</textarea>
|
||||
{% elif isinstance(item[1], bool) %}
|
||||
<div style="margin-left: 30px;">
|
||||
{% if item[1] == True %}
|
||||
@ -123,11 +116,9 @@
|
||||
{% end %}
|
||||
</div>
|
||||
{% elif isinstance(item[1], int) %}
|
||||
<input type="number" class="form-control" name="{{item[0]}}" id="{{item[0]}}" value="{{ item[1] }}"
|
||||
step="1" min="0" required>
|
||||
<input type="number" class="form-control" name="{{item[0]}}" id="{{item[0]}}" value="{{ item[1] }}" step="1" min="0" required>
|
||||
{% else %}
|
||||
<input type="text" class="form-control" name="{{item[0]}}" id="{{item[0]}}" value="{{ item[1] }}"
|
||||
step="2" min="0" required>
|
||||
<input type="text" class="form-control" name="{{item[0]}}" id="{{item[0]}}" value="{{ item[1] }}" step="2" min="0" required>
|
||||
{% end %}
|
||||
</div>
|
||||
{% end %}
|
||||
@ -142,10 +133,6 @@
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.custom-picker {
|
||||
border: 1px solid var(--outline);
|
||||
}
|
||||
|
||||
.dropdown-menu.inner {
|
||||
display: inline-block !important;
|
||||
}
|
||||
|
@ -28,7 +28,12 @@
|
||||
|
||||
|
||||
{% if data['superuser'] %}
|
||||
<span class="d-none d-sm-block">
|
||||
{% include "parts/crafty_config_list.html %}
|
||||
</span>
|
||||
<span class="d-block d-sm-none">
|
||||
{% include "parts/m_crafty_config_list.html %}
|
||||
</span>
|
||||
{% end %}
|
||||
|
||||
<!-- Page Title Header Starts-->
|
||||
@ -51,16 +56,19 @@
|
||||
<div class="col-12">
|
||||
<h4>{{ translate('customLogin', 'loginImage', data['lang']) }}</h4>
|
||||
<hr>
|
||||
<form class="form-row" name="zip" method="post" class="server-wizard" onSubmit="wait_msg(true)">
|
||||
<form class="form" name="zip" method="post" class="server-wizard" onSubmit="wait_msg(true)">
|
||||
{% raw xsrf_form_html() %}
|
||||
<input type="hidden" value="import_zip" name="create_type">
|
||||
<div class="col form-group">
|
||||
<span id="upload_input"><input type="file" class="form-control-file" id="file" name="file"
|
||||
multiple="false" required></span>
|
||||
<div class="form-group">
|
||||
<div id="upload_input" class="input-group">
|
||||
<div class="custom-file">
|
||||
<input type="file" class="custom-file-input" id="file" name="file" multiple="false" required>
|
||||
<label id="fileLabel" class="custom-file-label" for="file">{{ translate('customLogin', 'labelLoginImage', data['lang']) }}</label>
|
||||
</div>
|
||||
<div class="input-group-append">
|
||||
<button type="button" class="btn btn-info upload-button" id="upload-button" onclick="sendFile()" disabled>UPLOAD</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col form-group">
|
||||
<button type="button" class="btn btn-info" id="upload-button" onclick="sendFile()"
|
||||
disabled>UPLOAD</button>
|
||||
</div>
|
||||
</form>
|
||||
<hr>
|
||||
@ -73,8 +81,7 @@
|
||||
<div class="form-group row">
|
||||
<label for="photo" class="col-sm-6 col-form-label">Selected Background Image</label>
|
||||
<div class="col-sm-6">
|
||||
<select class="form-select form-control form-control-lg select-css form-control-plaintext"
|
||||
id="photo" name="photo" form="photo_form" onchange="updateBackgroundPreview()">
|
||||
<select class="form-select form-control form-control-lg select-css form-control-plaintext" id="photo" name="photo" form="photo_form" onchange="updateBackgroundPreview()">
|
||||
{% for image in data["backgrounds"] %}
|
||||
<option value="{{image}}">{{image}}</option>
|
||||
{% end %}
|
||||
@ -83,9 +90,7 @@
|
||||
</div>
|
||||
<div id="photo_loading" class="form-group" hidden>
|
||||
<div class="progress">
|
||||
<div class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar"
|
||||
aria-valuenow="100" aria-valuemin="0" aria-valuemax="100" style="width: 100%"> <i
|
||||
class="fa-solid fa-spinner"></i></div>
|
||||
<div class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100" style="width: 100%"> <i class="fa-solid fa-spinner"></i></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
@ -93,13 +98,11 @@
|
||||
data['lang']) }}</label>
|
||||
<label class="col-sm-1" id="opacityValue">{{ data['login_opacity'] }}%</label>
|
||||
<div class="range col-sm-8">
|
||||
<input type="range" class="form-control-range" id="modal_opacity" name="modal_opacity"
|
||||
onchange="previewOpacity()" min="0" max="100" value="{{ data['login_opacity'] }}">
|
||||
<input type="range" class="form-control-range" id="modal_opacity" name="modal_opacity" onchange="previewOpacity()" min="0" max="100" value="{{ data['login_opacity'] }}">
|
||||
</div>
|
||||
</div>
|
||||
<div id="login_preview" style="position: relative;">
|
||||
<img id="bg-preview" src="../../static/assets/images/auth/{{ data['background'] }}"
|
||||
class="img-fluid" alt="Responsive image">
|
||||
<img id="bg-preview" src="../../static/assets/images/auth/{{ data['background'] }}" class="img-fluid" alt="Responsive image">
|
||||
<div id="login-form-preview">
|
||||
<div id="login-form-background" class="auto-form-wrapper login-modal">
|
||||
<div class="text-center auto-form-logo">
|
||||
@ -163,20 +166,17 @@
|
||||
</style>
|
||||
|
||||
<div id="login_form_data">
|
||||
<input type="hidden" name="_xsrf"
|
||||
value="2|1d603267|809fb6bd82f677d440e484dde7c3a310|1671726040" disabled>
|
||||
<input type="hidden" name="_xsrf" value="2|1d603267|809fb6bd82f677d440e484dde7c3a310|1671726040" disabled>
|
||||
<div class="form-group">
|
||||
<label class="label">Username</label>
|
||||
<div class="input-group">
|
||||
<input type="text" class="form-control login-text-input login-input"
|
||||
placeholder="Username" name="username" id="username" required="true" disabled>
|
||||
<input type="text" class="form-control login-text-input login-input" placeholder="Username" name="username" id="username" required="true" disabled>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="label">Password</label>
|
||||
<div class="input-group">
|
||||
<input type="password" class="form-control login-text-input login-input"
|
||||
placeholder="Password" name="password" id="password" required="true" disabled>
|
||||
<input type="password" class="form-control login-text-input login-input" placeholder="Password" name="password" id="password" required="true" disabled>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
@ -195,8 +195,7 @@
|
||||
<a href="#" class="text-small forgot-password" disabled>Forgot Password</a>
|
||||
</div>
|
||||
<div class="text-block text-center my-3">
|
||||
<span class="text-small font-weight-semibold"><a
|
||||
href="https://craftycontrol.com/">Crafty Control
|
||||
<span class="text-small font-weight-semibold"><a href="https://craftycontrol.com/">Crafty Control
|
||||
4.0.20</a> </span>
|
||||
</div>
|
||||
</div>
|
||||
@ -228,6 +227,10 @@
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.img-fluid {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.popover-body {
|
||||
color: white !important;
|
||||
;
|
||||
@ -272,6 +275,7 @@
|
||||
console.log("File changed");
|
||||
if ($('#file').val()) {
|
||||
$('#upload-button').prop("disabled", false);
|
||||
document.getElementById("fileLabel").innerHTML = $('#file').val().split('\\').pop().split('/').pop();
|
||||
console.log("File changed good");
|
||||
}
|
||||
});
|
||||
@ -352,7 +356,7 @@
|
||||
var file;
|
||||
function sendFile() {
|
||||
file = $("#file")[0].files[0]
|
||||
document.getElementById("upload_input").innerHTML = '<div class="progress"><div id="upload-progress-bar" class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100" style="width: 100%"> <i class="fa-solid fa-spinner"></i></div></div>';
|
||||
document.getElementById("upload_input").innerHTML = '<div class="progress" style="width: 100%"><div class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100" style="width: 100%"> <i class="fa-solid fa-spinner"></i></div></div>';
|
||||
let xmlHttpRequest = new XMLHttpRequest();
|
||||
let token = getCookie("_xsrf")
|
||||
let fileName = file.name
|
||||
@ -380,7 +384,7 @@
|
||||
xmlHttpRequest.addEventListener('load', (event) => {
|
||||
if (event.target.responseText == 'success') {
|
||||
console.log('Upload for file', file.name, 'was successful!')
|
||||
document.getElementById("upload_input").innerHTML = '<div class="card-header header-sm d-flex justify-content-between align-items-center"><span id="file-uploaded" style="color: gray;">' + fileName + '</span> 🔒</div>';
|
||||
document.getElementById("upload_input").innerHTML = '<div class="card-header header-sm d-flex justify-content-between align-items-center" style="width: 100%"><span id="file-uploaded" style="color: gray;">' + fileName + '</span> 🔒</div>';
|
||||
setTimeout(function () {
|
||||
window.location.reload();
|
||||
}, 2000);
|
||||
|
@ -647,10 +647,13 @@
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
headers: { 'X-XSRFToken': token },
|
||||
url: '/server/command?command=' + command + '&id=' + server_id,
|
||||
url: `/api/v2/servers/${server_id}/action/${command}`,
|
||||
success: function (data) {
|
||||
console.log("got response:");
|
||||
console.log(data);
|
||||
if (command === "clone_server" && data.status === "ok") {
|
||||
window.location.reload();
|
||||
}
|
||||
/*setTimeout(function () {
|
||||
if (command != 'start_server') {
|
||||
location.reload();
|
||||
@ -705,24 +708,6 @@
|
||||
document.querySelector('.dynamicMsg').appendChild(parentEl);
|
||||
}
|
||||
|
||||
function send_kill(server_id) {
|
||||
/* this getCookie function is in base.html */
|
||||
const token = getCookie("_xsrf");
|
||||
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
headers: { 'X-XSRFToken': token },
|
||||
url: '/ajax/kill?id=' + server_id,
|
||||
success: function (data) {
|
||||
console.log("got response:");
|
||||
console.log(data);
|
||||
/*setTimeout(function () {
|
||||
location.reload();
|
||||
}, 10000);*/
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function update_one_server_status(server) {
|
||||
/* Mobile view update */
|
||||
server_cpu = document.getElementById('server_cpu_' + server.id);
|
||||
@ -901,17 +886,11 @@
|
||||
},
|
||||
callback: function (result) {
|
||||
if (result) {
|
||||
send_kill(server_id);
|
||||
send_command(server_id, "kill_server");
|
||||
let dialog = bootbox.dialog({
|
||||
title: '{% raw translate("dashboard", "killing", data["lang"]) %}',
|
||||
message: '<p><i class="fa fa-spin fa-spinner"></i> Loading...</p>'
|
||||
});
|
||||
|
||||
dialog.init(function () {
|
||||
setTimeout(function () {
|
||||
location.reload();
|
||||
}, 15000);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -1000,16 +979,6 @@
|
||||
},
|
||||
callback: function (result) {
|
||||
if (result) {
|
||||
cloneServer(server_id);
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
function cloneServer(server_id) {
|
||||
send_command(server_id, 'clone_server');
|
||||
bootbox.dialog({
|
||||
backdrop: true,
|
||||
@ -1018,6 +987,12 @@
|
||||
closeButton: false,
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
</script>
|
||||
<script src="/static/assets/vendors/js/jquery-ui.js"></script>
|
||||
<link rel="stylesheet" href="/static/assets/vendors/css/jquery-ui.css">
|
||||
@ -1069,12 +1044,12 @@
|
||||
const token = getCookie("_xsrf")
|
||||
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
type: "PATCH",
|
||||
headers: { 'X-XSRFToken': token },
|
||||
url: '/ajax/send_order?order=' + id_string,
|
||||
data: {
|
||||
order: id_string,
|
||||
},
|
||||
url: `/api/v2/users/@me`,
|
||||
data: JSON.stringify({
|
||||
server_order: id_string,
|
||||
}),
|
||||
success: function (data) {
|
||||
console.log("got response:");
|
||||
console.log(data);
|
||||
|
@ -12,6 +12,15 @@
|
||||
<link rel="stylesheet" href="/static/assets/vendors/ti-icons/css/themify-icons.css">
|
||||
<link rel="stylesheet" href="/static/assets/vendors/typicons/typicons.css">
|
||||
<link rel="stylesheet" href="/static/assets/vendors/css/vendor.bundle.base.css">
|
||||
|
||||
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<meta name="mobile-web-app-capable" content="yes" />
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black">
|
||||
<meta name="apple-mobile-web-app-title" content="Crafty">
|
||||
<link rel="apple-touch-icon" href="../static/assets/images/Crafty_4-0.png">
|
||||
|
||||
|
||||
<!-- endinject -->
|
||||
<!-- Plugin css for this page -->
|
||||
<!-- End Plugin css for this page -->
|
||||
@ -24,7 +33,7 @@
|
||||
<style>
|
||||
.auth.auth-bg-1 {
|
||||
background: url("../../static/assets/images/auth/{% raw data['background'] %}"),
|
||||
url("../../static/assets/images/auth/login-1.jpg");
|
||||
url("/static/assets/images/auth/login_1.jpg");
|
||||
background-size: cover;
|
||||
}
|
||||
</style>
|
||||
@ -77,6 +86,21 @@
|
||||
<script src="/static/assets/js/shared/settings.js"></script>
|
||||
<script src="/static/assets/js/shared/todolist.js"></script>
|
||||
<!-- endinject -->
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
let login_opacity_div = document.getElementById('login_opacity');
|
||||
let opacity = login_opacity_div.getAttribute('data-value');
|
||||
document.getElementById('login-form-background').style.background = 'rgb(34, 36, 55, ' + (opacity / 100) + ')';
|
||||
//Register Service worker for mobile app
|
||||
if ('serviceWorker' in navigator) {
|
||||
navigator.serviceWorker.register('/static/assets/js/shared/service-worker.js', {scope: '/'})
|
||||
.then(function (registration) {
|
||||
console.error('Service Worker Registered');
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
@ -28,7 +28,12 @@
|
||||
|
||||
|
||||
{% if data['superuser'] %}
|
||||
<span class="d-none d-sm-block">
|
||||
{% include "parts/crafty_config_list.html %}
|
||||
</span>
|
||||
<span class="d-block d-sm-none">
|
||||
{% include "parts/m_crafty_config_list.html %}
|
||||
</span>
|
||||
{% end %}
|
||||
|
||||
<!-- Page Title Header Starts-->
|
||||
|
@ -321,9 +321,60 @@
|
||||
return r ? r[1] : undefined;
|
||||
}
|
||||
|
||||
function gather_server_json() {
|
||||
servers = [];
|
||||
for (s = 0; s < page_servers.length; s++){
|
||||
mask = ""
|
||||
for (i = 0; i < permissions.length; i++){
|
||||
if ($(`#permission_${page_servers[s].id}_${permissions[i]}`).prop('checked')){
|
||||
mask += "1"
|
||||
}else{
|
||||
mask += "0"
|
||||
}
|
||||
}
|
||||
servers.push(JSON.stringify({"id": page_servers[s].id, "permissions": mask}));
|
||||
}
|
||||
return servers;
|
||||
}
|
||||
|
||||
$( document ).ready(function() {
|
||||
console.log( "ready!" );
|
||||
});
|
||||
const roleId = new URLSearchParams(document.location.search).get('id');
|
||||
|
||||
$("#config_form").on("submit", async function (e) {
|
||||
e.preventDefault();
|
||||
var token = getCookie("_xsrf")
|
||||
let configForm = document.getElementById("config_form");
|
||||
|
||||
let formData = new FormData(configForm);
|
||||
//Create an object from the form data entries
|
||||
let formDataObject = Object.fromEntries(formData.entries());
|
||||
let send_object = Object()
|
||||
send_object.servers = []
|
||||
send_object.name = formDataObject.role_name
|
||||
|
||||
// Format the plain form data as JSON
|
||||
let formDataJsonString = JSON.stringify(formDataObject, replacer);
|
||||
|
||||
let res = await fetch(`/api/v2/roles/${roleId}`, {
|
||||
method: 'PATCH',
|
||||
headers: {
|
||||
'X-XSRFToken': token
|
||||
},
|
||||
body: formDataJsonString,
|
||||
});
|
||||
let responseData = await res.json();
|
||||
if (responseData.status === "ok") {
|
||||
window.location.reload();
|
||||
} else {
|
||||
|
||||
bootbox.alert({
|
||||
title: responseData.error,
|
||||
message: responseData.error_data
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
</script>
|
||||
|
@ -1,17 +1,14 @@
|
||||
<ul class="nav nav-tabs col-md-12 tab-simple-styled" role="tablist" style="margin-top: 0;">
|
||||
<li class="nav-item term-nav-item">
|
||||
<a class="nav-link {% if data['active_link'] == 'panel_config' %}active{% end %}" href="/panel/panel_config"
|
||||
role="tab" aria-selected="false">
|
||||
<i class="fa-solid fa-wrench"></i>{{ translate('panelConfig', 'pageTitle', data['lang']) }}</a>
|
||||
<a class="nav-link {% if data['active_link'] == 'panel_config' %}active{% end %}" href="/panel/panel_config" role="tab" aria-selected="false">
|
||||
<i class="fas fa-wrench"></i>{{ translate('panelConfig', 'pageTitle', data['lang']) }}</a>
|
||||
</li>
|
||||
<li class="nav-item term-nav-item">
|
||||
<a class="nav-link {% if data['active_link'] == 'config_json' %}active{% end %}" href="/panel/config_json"
|
||||
role="tab" aria-selected="false">
|
||||
<i class="fa-solid fa-code"></i>{{ translate('panelConfig', 'json', data['lang']) }}</a>
|
||||
<a class="nav-link {% if data['active_link'] == 'config_json' %}active{% end %}" href="/panel/config_json" role="tab" aria-selected="false">
|
||||
<i class="fas fa-code"></i>{{ translate('panelConfig', 'json', data['lang']) }}</a>
|
||||
</li>
|
||||
<li class="nav-item term-nav-item">
|
||||
<a class="nav-link {% if data['active_link'] == 'custom_login' %}active{% end %}" href="/panel/custom_login"
|
||||
role="tab" aria-selected="false">
|
||||
<i class="fa fa-palette"></i>{{ translate('panelConfig', 'custom', data['lang']) }}</a>
|
||||
<a class="nav-link {% if data['active_link'] == 'custom_login' %}active{% end %}" href="/panel/custom_login" role="tab" aria-selected="false">
|
||||
<i class="fas fa-palette"></i>{{ translate('panelConfig', 'custom', data['lang']) }}</a>
|
||||
</li>
|
||||
</ul>
|
@ -228,6 +228,24 @@
|
||||
}
|
||||
|
||||
initParser('input_motd', 'input_motd');
|
||||
let text = ""
|
||||
let players = server.players_cache;
|
||||
for(let i=0; i < players.length; i++){
|
||||
text += `<tr id="playerItem-${ players[i]["name"] }" class="playerItem--" style="text-align: center;">`;
|
||||
text += `<td class="no-scroll" style="overflow: scroll;"><strong>${players[i]["name"]}</strong></td>`;
|
||||
if(players[i]["status"] === "Online"){
|
||||
text += `<td><span class="text-success"><i class="fas fa-signal"></i> ${ players[i]['status'] }</span></td>`
|
||||
}else{
|
||||
text += `<td><span class="text-warning"><i class="fa-regular fa-circle-xmark"></i><span class="offline-status"> ${ players[i]['status'] }</span><span class="conn-break"> Last connection :<br> ${ players[i]['last_seen'] }</span></td>`
|
||||
}
|
||||
if(server["running"]){
|
||||
text += `<td><button onclick="send_command_to_server('ban ${ players[i]['name'] }')" type="button" class="btn btn-danger controls">Ban</button><br class="mobile-break"><button onclick="send_command_to_server('kick ${ players[i]['name'] }')" type="button" class="btn btn-outline-danger controls">Kick</button><br><button onclick="send_command_to_server('op ${ players[i]['name'] }')" type="button" class="btn btn-warning controls">OP</button><br class="mobile-break"><button onclick="send_command_to_server('deop ${ players[i]['name'] }')" type="button" class="btn btn-outline-warning controls">De-OP</button></td>`
|
||||
}else{
|
||||
text += `<td><span> Unavailable<br> (Server Offline)</span></td>`
|
||||
}
|
||||
|
||||
}
|
||||
$("#player-body").html(text);
|
||||
|
||||
}
|
||||
|
||||
|
15
app/frontend/templates/panel/parts/m_crafty_config_list.html
Normal file
15
app/frontend/templates/panel/parts/m_crafty_config_list.html
Normal file
@ -0,0 +1,15 @@
|
||||
<div class="col-sm-12 mt-4 mb-4">
|
||||
<div class="dropdown">
|
||||
<button class="btn btn-outline dropdown-toggle custom-picker" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-expanded="false">
|
||||
<i class="fas fa-bars"></i> Crafty Config
|
||||
</button>
|
||||
<div class="dropdown-menu col-md-12" aria-labelledby="dropdownMenuButton">
|
||||
<a class="dropdown-item {% if data['active_link'] == 'panel_config' %}active{% end %}" href="/panel/panel_config" role="tab" aria-selected="false">
|
||||
<i class="fas fa-wrench"></i> Panel Config</a>
|
||||
<a class="dropdown-item {% if data['active_link'] == 'config_json' %}active{% end %}" href="/panel/config_json" role="tab" aria-selected="false">
|
||||
<i class="fas fa-code"></i> Config.json</a>
|
||||
<a class="dropdown-item {% if data['active_link'] == 'custom_login' %}active{% end %}" href="/panel/custom_login" role="tab" aria-selected="false">
|
||||
<i class="fas fa-palette"></i> Custom Login</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -1,7 +1,7 @@
|
||||
<div class="col-sm-12 mt-4 mb-4">
|
||||
<div class="dropdown">
|
||||
<button class="btn btn-secondary dropdown-toggle" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-expanded="false">
|
||||
Server Controls
|
||||
<button class="btn btn-outline dropdown-toggle custom-picker" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-expanded="false">
|
||||
<i class="fas fa-bars"></i> Server Controls
|
||||
</button>
|
||||
<div class="dropdown-menu col-md-12" aria-labelledby="dropdownMenuButton">
|
||||
{% if data['permissions']['Terminal'] in data['user_permissions'] %}
|
||||
@ -12,7 +12,7 @@
|
||||
<a class="dropdown-item {% if data['active_link'] == 'logs' %}active{% end %}" href="/panel/server_detail?id={{ data['server_stats']['server_id']['server_id'] }}&subpage=logs" role="tab" aria-selected="false"><i class="fa-solid fa-book-open-reader"></i> {{ translate('serverDetails', 'logs', data['lang']) }}</a>
|
||||
{% end %}
|
||||
{% if data['permissions']['Schedule'] in data['user_permissions'] %}
|
||||
<a class="dropdown-item {% if data['active_link'] == 'schedules' %}active{% end %}" href="/panel/server_detail?id={{ data['server_stats']['server_id']['server_id'] }}&subpage=schedules" role="tab" aria-selected="false"><i class="fas fa-clock"></i> {{ translate('serverDetails', 'schedule', data['lang']) }}</a>
|
||||
<a class="dropdown-item {% if data['active_link'] == 'schedules' %}active{% end %}" href="/panel/server_detail?id={{ data['server_stats']['server_id']['server_id'] }}&subpage=schedules" role="tab" aria-selected="false"><i class="fa-solid fa-clock"></i> {{ translate('serverDetails', 'schedule', data['lang']) }}</a>
|
||||
{% end %}
|
||||
{% if data['permissions']['Backup'] in data['user_permissions'] %}
|
||||
{% if data['backup_failed'] %}
|
||||
|
96
app/frontend/templates/panel/parts/server_players.html
Normal file
96
app/frontend/templates/panel/parts/server_players.html
Normal file
@ -0,0 +1,96 @@
|
||||
<div class="col-xl-6 col-lg-12 col-md-12 col-sm-12">
|
||||
<h2>{{ translate('serverPlayerManagement', 'players', data['lang']) }}:</h2>
|
||||
<table class="table table-sm-responsive">
|
||||
<thead class="thead">
|
||||
<tr>
|
||||
<th scope="col">Player</th>
|
||||
<th scope="col">Status</th>
|
||||
<th scope="col">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="player-body">
|
||||
{% for player in data['cached_players'] %}
|
||||
<tr id="playerItem-{{ player['name'] }}" class="playerItem--" style="text-align: center;">
|
||||
<td>
|
||||
<strong> {{ player['name'] }}</strong>
|
||||
</td>
|
||||
{% if player['status'] == 'Online' %}
|
||||
<td style="overflow: scroll;"><span class="text-success"><i class="fas fa-signal"></i> {{ player['status'] }}</span></td>
|
||||
{% elif player['status'] == 'Offline' %}
|
||||
<td><span class="text-warning"><i class="fa-regular fa-circle-xmark"></i><span class="offline-status"> {{ player['status'] }}</span><span class="conn-break"> Last connection :<br> {{ player['last_seen'] }}</span></span></td>
|
||||
{% end %}
|
||||
<td class="buttons" style="text-align: center;">
|
||||
{% if data['server_stats']['running'] %}
|
||||
<button onclick="send_command_to_server(`ban {{ player['name'] }}`)" type="button" class="btn btn-danger controls">Ban</button>
|
||||
<br class="mobile-break"/>
|
||||
<button onclick="send_command_to_server(`kick {{ player['name'] }}`)" type="button" class="btn btn-outline-danger controls">Kick</button>
|
||||
<br>
|
||||
<button onclick="send_command_to_server(`op {{ player['name'] }}`)" type="button" class="btn btn-warning controls">OP</button>
|
||||
<br class="mobile-break"/>
|
||||
<button onclick="send_command_to_server(`deop {{ player['name'] }}`)" type="button" class="btn btn-outline-warning controls">De-OP</button>
|
||||
{% else %}
|
||||
<span> Unavailable <br>(Server Offline)</span>
|
||||
{% end %}
|
||||
</td>
|
||||
</tr>
|
||||
{% end %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<style>
|
||||
@media (min-width: 600px) {
|
||||
.mobile-break { display: none;}
|
||||
.offline-status {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
@media screen and (max-width: 600px) {
|
||||
.conn-break { display: none; }
|
||||
}
|
||||
button.controls {
|
||||
width: 70px;
|
||||
}
|
||||
</style>
|
||||
<div class="col-xl-6 col-lg-12 col-md-12 col-sm-12 no-scroll" width="100%">
|
||||
<h2>{{ translate('serverPlayerManagement', 'bannedPlayers', data['lang']) }}:</h2>
|
||||
<table class="table table-sm-responsive d-none d-lg-block no-scroll" style="width: 100%;">
|
||||
<thead class="thead">
|
||||
<tr>
|
||||
<th scope="col">Player</th>
|
||||
<th scope="col">Status</th>
|
||||
<th scope="col">Reason</th>
|
||||
<th scope="col">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for player in data['banned_players'] %}
|
||||
<tr id="playerItem-{{ player }}" class="playerItem--">
|
||||
<td><strong> {{ player['name'] }}</strong></td>
|
||||
<td>Banned on {{ player['banned_on'] }}</td>
|
||||
<td>Banned by : {{ player['source'] }} <br />Reason : {{ player['reason'] }}</td>
|
||||
<td class="buttons">
|
||||
<button onclick="send_command_to_server(`pardon {{ player['name'] }} `)" type="button" class="btn btn-danger">Unban</button>
|
||||
</td>
|
||||
</tr>
|
||||
{% end %}
|
||||
</tbody>
|
||||
</table>
|
||||
<table class="table table-sm-responsive d-block d-lg-none" style="width: 100%;">
|
||||
<thead class="thead ">
|
||||
<tr>
|
||||
<th scope="col">Player</th>
|
||||
<th scope="col">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for player in data['banned_players'] %}
|
||||
<tr id="playerItem-{{ player }}" class="playerItem--">
|
||||
<td><strong> {{ player['name'] }}</strong></td>
|
||||
<td class="buttons">
|
||||
<button onclick="send_command_to_server(`pardon {{ player['name'] }} `)" type="button" class="btn btn-danger">Unban</button>
|
||||
</td>
|
||||
</tr>
|
||||
{% end %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
@ -14,7 +14,8 @@
|
||||
<div class="col-12">
|
||||
<div class="page-header">
|
||||
<h4 class="page-title">
|
||||
{{ translate('serverDetails', 'serverDetails', data['lang']) }} - {{ data['server_stats']['server_id']['server_name'] }}
|
||||
{{ translate('serverDetails', 'serverDetails', data['lang']) }} - {{
|
||||
data['server_stats']['server_id']['server_name'] }}
|
||||
<br />
|
||||
<small>UUID: {{ data['server_stats']['server_id']['server_uuid'] }}</small>
|
||||
</h4>
|
||||
@ -39,62 +40,10 @@
|
||||
</span>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6 col-sm-12">
|
||||
<style>
|
||||
.playerItem {
|
||||
padding: 1rem;
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin: 1rem 0px 1rem 0px;
|
||||
}
|
||||
|
||||
.playerItem h3 {
|
||||
vertical-align: middle;
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
margin-right: 1.5rem;
|
||||
}
|
||||
|
||||
.playerItem button {
|
||||
vertical-align: middle;
|
||||
margin: 0.25rem;
|
||||
}
|
||||
|
||||
.playerUnban {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.banned span {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
</style>
|
||||
<h2>{{ translate('serverPlayerManagement', 'players', data['lang']) }}:</h2>
|
||||
<ul style="list-style: none;padding: 0px;margin: 0px; margin-bottom: 1rem;gap: 1rem;">
|
||||
{% for player in data['get_players'] %}
|
||||
<li class="playerItem">
|
||||
<h3>{{ player }}</h3>
|
||||
<div class="buttons">
|
||||
<button onclick="send_command_to_server('ban {{ player }}')" type="button" class="btn btn-danger">Ban</button>
|
||||
<button onclick="send_command_to_server('kick {{ player }}')" type="button" class="btn btn-outline-danger">Kick</button>
|
||||
<button onclick="send_command_to_server('op {{ player }}')" type="button" class="btn btn-warning">OP</button>
|
||||
<button onclick="send_command_to_server('deop {{ player }}')" type="button" class="btn btn-outline-warning">De-OP</button>
|
||||
{% include "parts/server_players.html %}
|
||||
</div>
|
||||
</li>
|
||||
{% end %}
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-md-6 col-sm-12">
|
||||
<h2>{{ translate('serverPlayerManagement', 'bannedPlayers', data['lang']) }}:</h2>
|
||||
<ul id="bannedPlayers" style="list-style: none;padding: 0px;margin: 0px; margin-bottom: 1rem;gap: 1rem;">
|
||||
<li class="playerItem banned">
|
||||
<h3>{{ translate('serverPlayerManagement', 'loadingBannedPlayers', data['lang']) }}</h3>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<hr />
|
||||
|
||||
</div>
|
||||
</div>
|
||||
@ -128,7 +77,7 @@
|
||||
$(document).ready(function () {
|
||||
console.log("ready!");
|
||||
|
||||
var bannedPlayers = `{{ data['banned_players'] }}`;
|
||||
var bannedPlayers = `{{ data['banned_players_html'] }}`;
|
||||
|
||||
var bannedPlayersDecoded = htmlDecode(bannedPlayers);
|
||||
|
||||
@ -136,21 +85,22 @@
|
||||
|
||||
});
|
||||
|
||||
function send_command_to_server(command) {
|
||||
async function send_command_to_server(command) {
|
||||
console.log(command)
|
||||
var token = getCookie("_xsrf")
|
||||
console.log('sending command: ' + command)
|
||||
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
headers: { 'X-XSRFToken': token },
|
||||
url: '/ajax/send_command?id=' + serverId,
|
||||
data: { command },
|
||||
success: function (data) {
|
||||
console.log("got response:");
|
||||
console.log(data);
|
||||
let res = await fetch(`/api/v2/servers/${serverId}/stdin`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'X-XSRFToken': token
|
||||
},
|
||||
body: command,
|
||||
});
|
||||
|
||||
let responseData = await res.text();
|
||||
console.log("got response:");
|
||||
console.log(responseData);
|
||||
}
|
||||
|
||||
|
||||
|
@ -326,7 +326,7 @@
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
headers: { 'X-XSRFToken': token },
|
||||
url: '/ajax/backup_now?id=' + server_id,
|
||||
url: `/api/v2/servers/${server_id}/action/backup_server`,
|
||||
success: function (data) {
|
||||
return;
|
||||
},
|
||||
|
@ -43,49 +43,36 @@
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6 col-sm-12">
|
||||
<form class="forms-sample" method="post" id="config_form" action="/panel/server_detail">
|
||||
{% raw xsrf_form_html() %}
|
||||
<input type="hidden" name="id" value="{{ data['server_stats']['server_id']['server_id'] }}">
|
||||
<input type="hidden" name="subpage" value="config">
|
||||
<form class="forms-sample" method="post" id="config_form">
|
||||
|
||||
<div class="form-group">
|
||||
<label for="server_name">{{ translate('serverConfig', 'serverName', data['lang']) }} <small
|
||||
class="text-muted ml-1"> - {{ translate('serverConfig', 'serverNameDesc', data['lang']) }}</small>
|
||||
<label for="server_name">{{ translate('serverConfig', 'serverName', data['lang']) }} <small class="text-muted ml-1"> - {{ translate('serverConfig', 'serverNameDesc', data['lang']) }}</small>
|
||||
</label>
|
||||
<input type="text" class="form-control" name="server_name" id="server_name"
|
||||
value="{{ data['server_stats']['server_id']['server_name'] }}"
|
||||
placeholder="{{ translate('serverConfig', 'serverName', data['lang']) }}" required>
|
||||
<input type="text" class="form-control" name="server_name" id="server_name" value="{{ data['server_stats']['server_id']['server_name'] }}" placeholder="{{ translate('serverConfig', 'serverName', data['lang']) }}" required>
|
||||
</div>
|
||||
|
||||
{% if data['super_user'] %}
|
||||
<div class="form-group">
|
||||
<label for="server_path">{{ translate('serverConfig', 'serverPath', data['lang']) }} <small
|
||||
class="text-muted ml-1"> - {{ translate('serverConfig', 'serverPathDesc', data['lang']) }}</small>
|
||||
<label for="server_path">{{ translate('serverConfig', 'serverPath', data['lang']) }} <small class="text-muted ml-1"> - {{ translate('serverConfig', 'serverPathDesc', data['lang']) }}</small>
|
||||
</label>
|
||||
<div class="card-header header-sm d-flex justify-content-between align-items-center">
|
||||
<span style="color: gray; font-size: 12px;">{{ data['server_stats']['server_id']['path'] }}</span>
|
||||
<span style="color: gray; font-size: .9vw;">{{ data['server_stats']['server_id']['path'] }}</span>
|
||||
🔒
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{% if data['server_stats']['server_type'] != "minecraft-bedrock" %}
|
||||
<div class="form-group">
|
||||
<label for="log_path">{{ translate('serverConfig', 'serverLogLocation', data['lang']) }} <small
|
||||
class="text-muted ml-1"> - {{ translate('serverConfig', 'serverLogLocationDesc', data['lang'])
|
||||
<label for="log_path">{{ translate('serverConfig', 'serverLogLocation', data['lang']) }} <small class="text-muted ml-1"> - {{ translate('serverConfig', 'serverLogLocationDesc', data['lang'])
|
||||
}}</small> </label>
|
||||
<input type="text" class="form-control" name="log_path" id="log_path"
|
||||
value="{{ data['server_stats']['server_id']['log_path'] }}"
|
||||
placeholder="{{ translate('serverConfig', 'serverLogLocation', data['lang']) }}" required>
|
||||
<input type="text" class="form-control" name="log_path" id="log_path" value="{{ data['server_stats']['server_id']['log_path'] }}" placeholder="{{ translate('serverConfig', 'serverLogLocation', data['lang']) }}" required>
|
||||
</div>
|
||||
{% end %}
|
||||
|
||||
<div class="form-group">
|
||||
<label for="executable">{{ translate('serverConfig', 'serverExecutable', data['lang']) }} <small
|
||||
class="text-muted ml-1"> - {{ translate('serverConfig', 'serverExecutableDesc', data['lang'])
|
||||
<label for="executable">{{ translate('serverConfig', 'serverExecutable', data['lang']) }} <small class="text-muted ml-1"> - {{ translate('serverConfig', 'serverExecutableDesc', data['lang'])
|
||||
}}</small> </label>
|
||||
<input type="text" class="form-control" name="executable" id="executable"
|
||||
value="{{ data['server_stats']['server_id']['executable'] }}"
|
||||
placeholder="{{ translate('serverConfig', 'serverExecutable', data['lang']) }}" required>
|
||||
<input type="text" class="form-control" name="executable" id="executable" value="{{ data['server_stats']['server_id']['executable'] }}" placeholder="{{ translate('serverConfig', 'serverExecutable', data['lang']) }}" required>
|
||||
</div>
|
||||
{% end %}
|
||||
{% if data['server_stats']['server_type'] == "minecraft-java" %}
|
||||
@ -94,10 +81,8 @@
|
||||
<small class="text-muted ml-1">{{ translate('serverConfig', 'javaVersionDesc', data['lang'])
|
||||
}}</small>
|
||||
</label>
|
||||
<select class="form-select form-control form-control-lg select-css" id="java_selection"
|
||||
name="java_selection" form="config_form">
|
||||
<option value="">{{ translate('serverConfig',
|
||||
'javaNoChange', data['lang'])}}</option>
|
||||
<select class="form-select form-control form-control-lg select-css" id="java_selection" name="java_selection" form="config_form">
|
||||
<option value="none">{{ translate('serverConfig', 'javaNoChange', data['lang'])}}</option>
|
||||
{% for path in data['java_versions'] %}
|
||||
<option value="{{path}}">{{path}}</option>
|
||||
{% end %}
|
||||
@ -110,33 +95,26 @@
|
||||
<label for="execution_command">{{ translate('serverConfig', 'serverExecutionCommand', data['lang']) }}
|
||||
<small class="text-muted ml-1"> - {{ translate('serverConfig', 'serverExecutionCommandDesc',
|
||||
data['lang']) }}</small> </label>
|
||||
<input type="text" class="form-control" name="execution_command" id="execution_command"
|
||||
value="{{ data['server_stats']['server_id']['execution_command'] }}"
|
||||
placeholder="{{ translate('serverConfig', 'serverExecutionCommand', data['lang']) }}" required>
|
||||
<input type="text" class="form-control" name="execution_command" id="execution_command" value="{{ data['server_stats']['server_id']['execution_command'] }}" placeholder="{{ translate('serverConfig', 'serverExecutionCommand', data['lang']) }}" required>
|
||||
</div>
|
||||
{% else %}
|
||||
<label for="execution_command">{{ translate('serverConfig', 'serverExecutionCommand', data['lang']) }}
|
||||
<div class="card-header header-sm d-flex justify-content-between align-items-center">
|
||||
<span style="color: gray;">{{ data['server_stats']['server_id']['execution_command'] }}</span> 🔒
|
||||
<span style="color: gray; font-size: .9vw;">{{ data['server_stats']['server_id']['execution_command'] }}</span> 🔒
|
||||
</div>
|
||||
<br>
|
||||
{% end %}
|
||||
<div class="form-group">
|
||||
<label for="stop_command">{{ translate('serverConfig', 'serverStopCommand', data['lang']) }} <small
|
||||
class="text-muted ml-1"> - {{ translate('serverConfig', 'serverStopCommandDesc', data['lang'])
|
||||
<label for="stop_command">{{ translate('serverConfig', 'serverStopCommand', data['lang']) }} <small class="text-muted ml-1"> - {{ translate('serverConfig', 'serverStopCommandDesc', data['lang'])
|
||||
}}</small> </label>
|
||||
<input type="text" class="form-control" name="stop_command" id="stop_command"
|
||||
value="{{ data['server_stats']['server_id']['stop_command'] }}"
|
||||
placeholder="{{ translate('serverConfig', 'serverStopCommand', data['lang']) }}" required>
|
||||
<input type="text" class="form-control" name="stop_command" id="stop_command" value="{{ data['server_stats']['server_id']['stop_command'] }}" placeholder="{{ translate('serverConfig', 'serverStopCommand', data['lang']) }}" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="auto_start_delay">{{ translate('serverConfig', 'serverAutostartDelay', data['lang']) }}
|
||||
<small class="text-muted ml-1"> - {{ translate('serverConfig', 'serverAutostartDelayDesc',
|
||||
data['lang']) }}</small> </label>
|
||||
<input type="number" class="form-control" name="auto_start_delay" id="auto_start_delay"
|
||||
value="{{ data['server_stats']['server_id']['auto_start_delay'] }}" step="1" max="999" min="10"
|
||||
required>
|
||||
<input type="number" class="form-control" name="auto_start_delay" id="auto_start_delay" value="{{ data['server_stats']['server_id']['auto_start_delay'] }}" step="1" max="999" min="10" required>
|
||||
</div>
|
||||
|
||||
{% if data['super_user'] %}
|
||||
@ -145,31 +123,21 @@
|
||||
<label for="executable_update_url">{{ translate('serverConfig', 'exeUpdateURL', data['lang']) }}
|
||||
<small class="text-muted ml-1"> - {{ translate('serverConfig', 'exeUpdateURLDesc', data['lang'])
|
||||
}}</small> </label>
|
||||
<input type="text" class="form-control" name="executable_update_url" id="executable_update_url"
|
||||
value="{{ data['server_stats']['server_id']['executable_update_url'] }}"
|
||||
placeholder="{{ translate('serverConfig', 'exeUpdateURL', data['lang']) }}">
|
||||
<input type="text" class="form-control" name="executable_update_url" id="executable_update_url" value="{{ data['server_stats']['server_id']['executable_update_url'] }}" placeholder="{{ translate('serverConfig', 'exeUpdateURL', data['lang']) }}">
|
||||
</div>
|
||||
{% end %}
|
||||
|
||||
<div class="form-group">
|
||||
<label for="server_ip">{{ translate('serverConfig', 'serverIP', data['lang']) }} <small
|
||||
class="text-muted ml-1">- {{ translate('serverConfig', 'serverIPDesc', data['lang']) }}</small>
|
||||
<label for="server_ip">{{ translate('serverConfig', 'serverIP', data['lang']) }} <small class="text-muted ml-1">- {{ translate('serverConfig', 'serverIPDesc', data['lang']) }}</small>
|
||||
</label>
|
||||
<input type="text" class="form-control" name="server_ip" id="server_ip"
|
||||
value="{{ data['server_stats']['server_id']['server_ip'] }}" required>
|
||||
<input type="text" class="form-control" name="server_ip" id="server_ip" value="{{ data['server_stats']['server_id']['server_ip'] }}" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="server_port">{{ translate('serverConfig', 'serverPort', data['lang']) }} <small
|
||||
class="text-muted ml-1"> - {{ translate('serverConfig', 'serverPortDesc', data['lang']) }}
|
||||
<label for="server_port">{{ translate('serverConfig', 'serverPort', data['lang']) }} <small class="text-muted ml-1"> - {{ translate('serverConfig', 'serverPortDesc', data['lang']) }}
|
||||
</small> </label>
|
||||
<input type="number" class="form-control" name="server_port" id="server_port"
|
||||
value="{{ data['server_stats']['server_id']['server_port'] }}" step="1" max="65566" min="1"
|
||||
required>
|
||||
<span data-html="true" class="port-hint text-center"
|
||||
title="<i class='fal fa-exclamation-triangle'></i> " ,
|
||||
data-content="{{
|
||||
translate('serverConfig', 'statsHint1' , data['lang'])}} <br> <br> <strong>{{ translate('serverConfig', 'statsHint2', data['lang'])}}</strong>" ,
|
||||
data-placement="right"></span>
|
||||
<input type="number" class="form-control" name="server_port" id="server_port" value="{{ data['server_stats']['server_id']['server_port'] }}" step="1" max="65566" min="1" required>
|
||||
<span data-html="true" class="port-hint text-center" title="<i class='fal fa-exclamation-triangle'></i> " , data-content="{{
|
||||
translate('serverConfig', 'statsHint1' , data['lang'])}} <br> <br> <strong>{{ translate('serverConfig', 'statsHint2', data['lang'])}}</strong>" , data-placement="right"></span>
|
||||
</div>
|
||||
{% end %}
|
||||
|
||||
@ -180,9 +148,7 @@
|
||||
{{ data['server_stats']['server_id']['stop_command'] }} {{ translate('serverConfig',
|
||||
'timeoutExplain2', data['lang']) }}
|
||||
</small> </label>
|
||||
<input type="number" class="form-control" name="shutdown_timeout" id="shutdown_timeout"
|
||||
value="{{ data['server_stats']['server_id']['shutdown_timeout'] }}" step="2" max="300" min="60"
|
||||
required>
|
||||
<input type="number" class="form-control" name="shutdown_timeout" id="shutdown_timeout" value="{{ data['server_stats']['server_id']['shutdown_timeout'] }}" step="2" max="300" min="60" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="ignored_exits">{{ translate('serverConfig', 'ignoredExits', data['lang']) }}
|
||||
@ -190,58 +156,51 @@
|
||||
data['lang'])
|
||||
}}
|
||||
</small> </label>
|
||||
<input type="text" class="form-control" name="ignored_exits" id="ignored_exits"
|
||||
value="{{ data['server_stats']['server_id']['ignored_exits'] }}">
|
||||
<input type="text" class="form-control" name="ignored_exits" id="ignored_exits" value="{{ data['server_stats']['server_id']['ignored_exits'] }}">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="logs_delete_after">{{ translate('serverConfig', 'removeOldLogsAfter', data['lang']) }}
|
||||
<small class="text-muted ml-1"> - {{ translate('serverConfig', 'removeOldLogsAfterDesc',
|
||||
data['lang']) }}</small> </label>
|
||||
<input type="number" class="form-control" name="logs_delete_after" id="logs_delete_after"
|
||||
value="{{ data['server_stats']['server_id']['logs_delete_after'] }}" step="1" max="365" min="0"
|
||||
required>
|
||||
<input type="number" class="form-control" name="logs_delete_after" id="logs_delete_after" value="{{ data['server_stats']['server_id']['logs_delete_after'] }}" step="1" max="365" min="0" required>
|
||||
</div>
|
||||
|
||||
<div class="form-check-flat">
|
||||
<label for="auto_start" class="form-check-label ml-4 mb-4">
|
||||
<div class="form-group">
|
||||
<div class="custom-control custom-switch">
|
||||
{% if data['server_stats']['server_id']['auto_start'] %}
|
||||
<input type="checkbox" class="form-check-input" id="auto_start" name="auto_start" checked=""
|
||||
data-toggle="toggle" value="1"> {{ translate('serverConfig', 'serverAutoStart',
|
||||
data['lang']) }}
|
||||
<input type="checkbox" class="custom-control-input" id="auto_start" name="auto_start" checked="" value="1">
|
||||
<label class="custom-control-label" for="auto_start"> {{ translate('serverConfig', 'serverAutoStart', data['lang']) }}</label>
|
||||
{% else %}
|
||||
<input type="checkbox" class="form-check-input" id="auto_start" name="auto_start" value="1"
|
||||
data-toggle="toggle"> {{
|
||||
translate('serverConfig', 'serverAutoStart', data['lang']) }}
|
||||
<input type="checkbox" class="custom-control-input" id="auto_start" name="auto_start" value="1">
|
||||
<label class="custom-control-label" for="auto_start"> {{ translate('serverConfig', 'serverAutoStart', data['lang']) }}</label>
|
||||
{% end %}
|
||||
</label>
|
||||
|
||||
<label for="crash_detection" class="form-check-label ml-4 mb-4">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="custom-control custom-switch">
|
||||
{% if data['server_stats']['server_id']['crash_detection'] %}
|
||||
<input type="checkbox" class="form-check-input" id="crash_detection" name="crash_detection"
|
||||
data-toggle="toggle" checked="" value="1"> {{ translate('serverConfig',
|
||||
'serverCrashDetection', data['lang']) }}
|
||||
<input type="checkbox" class="custom-control-input" id="crash_detection" name="crash_detection" checked="" value="1">
|
||||
<label class="custom-control-label" for="crash_detection"> {{ translate('serverConfig', 'serverCrashDetection', data['lang']) }}</label>
|
||||
{% else %}
|
||||
<input type="checkbox" class="form-check-input" id="crash_detection" name="crash_detection"
|
||||
data-toggle="toggle" value="1"> {{ translate('serverConfig', 'serverCrashDetection',
|
||||
data['lang']) }}
|
||||
<input type="checkbox" class="custom-control-input" id="crash_detection" name="crash_detection" value="1">
|
||||
<label class="custom-control-label" for="crash_detection"> {{ translate('serverConfig', 'serverCrashDetection', data['lang']) }}</label>
|
||||
{% end %}
|
||||
</label>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="custom-control custom-switch">
|
||||
{% if data['super_user'] %}
|
||||
<label for="show_status" class="form-check-label ml-4 mb-4">
|
||||
{% if data['server_stats']['server_id']['show_status'] %}
|
||||
<input type="checkbox" class="form-check-input" id="show_status" name="show_status"
|
||||
data-toggle="toggle" checked="" value="1"> {{ translate('serverConfig', 'showStatus',
|
||||
data['lang']) }}
|
||||
<input type="checkbox" class="custom-control-input" id="show_status" name="show_status" checked="" value="1">
|
||||
<label class="custom-control-label" for="show_status"> {{ translate('serverConfig', 'showStatus', data['lang']) }}</label>
|
||||
{% else %}
|
||||
<input type="checkbox" class="form-check-input" id="show_status" name="show_status"
|
||||
data-toggle="toggle" value="1"> {{ translate('serverConfig', 'showStatus',
|
||||
data['lang']) }}
|
||||
<input type="checkbox" class="custom-control-input" id="show_status" name="show_status" value="1">
|
||||
<label class="custom-control-label" for="show_status"> {{ translate('serverConfig', 'showStatus', data['lang']) }}</label>
|
||||
{% end %}
|
||||
</label>
|
||||
{% end %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-success mr-2"><i class="fas fa-save"></i> {{
|
||||
translate('serverConfig', 'save', data['lang']) }}</button>
|
||||
@ -265,14 +224,10 @@
|
||||
<div class="text-center">
|
||||
{% if data['server_stats']['running'] %}
|
||||
{% if data['server_stats']['updating'] %}
|
||||
<i id="update-spinner" class="fa fa-spinner fa-spin"></i> <button
|
||||
onclick="send_command(serverId, 'update_executable');" id="update_executable" style="max-width: 7rem;"
|
||||
class="btn btn-warning m-1 flex-grow-1 disabled">{{ translate('serverConfig',
|
||||
<i id="update-spinner" class="fa fa-spinner fa-spin"></i> <button onclick="send_command(serverId, 'update_executable');" id="update_executable" style="max-width: 7rem;" class="btn btn-warning m-1 flex-grow-1 disabled">{{ translate('serverConfig',
|
||||
'update', data['lang']) }}</button>
|
||||
{% else %}
|
||||
<i style="visibility: hidden;" id="update-spinner" class="fa fa-spinner fa-spin"></i> <button
|
||||
onclick="send_command(serverId, 'update_executable');" id="update_executable" style="max-width: 7rem;"
|
||||
class="btn btn-warning m-1 flex-grow-1 disabled">{{ translate('serverConfig',
|
||||
<i style="visibility: hidden;" id="update-spinner" class="fa fa-spinner fa-spin"></i> <button onclick="send_command(serverId, 'update_executable');" id="update_executable" style="max-width: 7rem;" class="btn btn-warning m-1 flex-grow-1 disabled">{{ translate('serverConfig',
|
||||
'update', data['lang']) }}</button>
|
||||
{% end %}
|
||||
<a class="btn btn-sm btn-danger disabled">{{ translate('serverConfig', 'deleteServer', data['lang'])
|
||||
@ -281,14 +236,10 @@
|
||||
{% else %}
|
||||
{% if not data['failed'] %}
|
||||
{% if data['server_stats']['updating'] %}
|
||||
<i id="update-spinner" class="fa fa-spinner fa-spin"></i> <button
|
||||
onclick="send_command(serverId, 'update_executable');" id="update_executable" style="max-width: 7rem;"
|
||||
class="btn btn-warning m-1 flex-grow-1">{{ translate('serverConfig',
|
||||
<i id="update-spinner" class="fa fa-spinner fa-spin"></i> <button onclick="send_command(serverId, 'update_executable');" id="update_executable" style="max-width: 7rem;" class="btn btn-warning m-1 flex-grow-1">{{ translate('serverConfig',
|
||||
'update', data['lang']) }}</button>
|
||||
{% else %}
|
||||
<i style="visibility: hidden;" id="update-spinner" class="fa fa-spinner fa-spin"></i> <button
|
||||
onclick="send_command(serverId, 'update_executable');" id="update_executable" style="max-width: 7rem;"
|
||||
class="btn btn-warning m-1 flex-grow-1">{{ translate('serverConfig',
|
||||
<i style="visibility: hidden;" id="update-spinner" class="fa fa-spinner fa-spin"></i> <button onclick="send_command(serverId, 'update_executable');" id="update_executable" style="max-width: 7rem;" class="btn btn-warning m-1 flex-grow-1">{{ translate('serverConfig',
|
||||
'update', data['lang']) }}</button>
|
||||
{% end %}
|
||||
{% end %}
|
||||
@ -304,28 +255,26 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
<style>
|
||||
.toggle-handle {
|
||||
background-color: white !important;
|
||||
}
|
||||
|
||||
.toggle-on {
|
||||
.custom-control-input:checked~.custom-control-label::before {
|
||||
color: black !important;
|
||||
background-color: blueviolet !important;
|
||||
border-color: var(--outline) !important;
|
||||
}
|
||||
|
||||
.toggle {
|
||||
height: 0px !important;
|
||||
background-color: grey !important;
|
||||
.custom-control-label::before {
|
||||
background-color: white !important;
|
||||
top: calc(-0.2rem);
|
||||
}
|
||||
|
||||
.custom-switch .custom-control-label::after {
|
||||
top: calc(-0.125rem + 1px);
|
||||
}
|
||||
</style>
|
||||
<!-- content-wrapper ends -->
|
||||
@ -359,7 +308,7 @@
|
||||
$.ajax({
|
||||
type: "DELETE",
|
||||
headers: { 'X-XSRFToken': token },
|
||||
url: '/ajax/delete_server?id=' + serverId,
|
||||
url: `/api/v2/servers/${serverId}`,
|
||||
data: {
|
||||
},
|
||||
success: function (data) {
|
||||
@ -373,7 +322,7 @@
|
||||
$.ajax({
|
||||
type: "DELETE",
|
||||
headers: { 'X-XSRFToken': token },
|
||||
url: '/ajax/delete_server_files?id=' + serverId,
|
||||
url: `/api/v2/servers/${serverId}?files=true`,
|
||||
data: {
|
||||
},
|
||||
success: function (data) {
|
||||
@ -393,7 +342,7 @@
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
headers: { 'X-XSRFToken': token },
|
||||
url: '/server/command?command=' + command + '&id=' + serverId,
|
||||
url: `/api/v2/servers/${serverId}/action/${command}`,
|
||||
success: function (data) {
|
||||
console.log("got response:");
|
||||
console.log(data);
|
||||
@ -522,7 +471,7 @@
|
||||
$.ajax({
|
||||
type: "DELETE",
|
||||
headers: { 'X-XSRFToken': token },
|
||||
url: '/ajax/delete_unloaded_server?id=' + serverId,
|
||||
url: `/api/v2/servers/${serverId}`,
|
||||
data: {
|
||||
},
|
||||
success: function (data) {
|
||||
@ -550,11 +499,92 @@
|
||||
$('.port-hint').popover("hide");
|
||||
});
|
||||
|
||||
async function postFormFieldsAsJson({ url, formData }) {
|
||||
//Create an object from the form data entries
|
||||
let formDataObject = Object.fromEntries(formData.entries());
|
||||
// Format the plain form data as JSON
|
||||
let formDataJsonString = JSON.stringify(formDataObject);
|
||||
|
||||
//Set the fetch options (headers, body)
|
||||
let fetchOptions = {
|
||||
//HTTP method set to POST.
|
||||
method: "PATCH",
|
||||
//Set the headers that specify you're sending a JSON body request and accepting JSON response
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Accept: "application/json",
|
||||
},
|
||||
// POST request body as JSON string.
|
||||
body: formDataJsonString,
|
||||
};
|
||||
|
||||
//Get the response body as JSON.
|
||||
//If the response was not OK, throw an error.
|
||||
let res = await fetch(url, fetchOptions);
|
||||
|
||||
//If the response is not ok throw an error (for debugging)
|
||||
if (!res.ok) {
|
||||
let error = await res.text();
|
||||
throw new Error(error);
|
||||
}
|
||||
//If the response was OK, return the response body.
|
||||
return res.json();
|
||||
}
|
||||
function replacer(key, value) {
|
||||
if (key != "ignored_exits") {
|
||||
if (typeof value == "boolean" || key === "executable_update_url") {
|
||||
return value
|
||||
} else {
|
||||
return (isNaN(value) ? value : +value);
|
||||
}
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
$(document).ready(function () {
|
||||
let token = getCookie("_xsrf")
|
||||
webSocket.on('remove_spinner', function () {
|
||||
document.getElementById("update-spinner").style.visibility = "hidden";
|
||||
});
|
||||
$("#config_form").on("submit", async function (e) {
|
||||
e.preventDefault();
|
||||
var token = getCookie("_xsrf")
|
||||
let configForm = document.getElementById("config_form");
|
||||
|
||||
let formData = new FormData(configForm);
|
||||
//Create an object from the form data entries
|
||||
let formDataObject = Object.fromEntries(formData.entries());
|
||||
//We need to make sure these are sent regardless of whether or not they're checked
|
||||
formDataObject.show_status = $("#show_status").prop('checked');
|
||||
formDataObject.crash_detection = $("#crash_detection").prop('checked');
|
||||
formDataObject.auto_start = $("#auto_start").prop('checked');
|
||||
console.log(formDataObject);
|
||||
// Format the plain form data as JSON
|
||||
let formDataJsonString = JSON.stringify(formDataObject, replacer);
|
||||
formDataJsonString["ignored_exits"] = toString(formDataJsonString["ignored_exits"]);
|
||||
console.log(formDataJsonString.ignored_exits)
|
||||
|
||||
console.log(formDataJsonString);
|
||||
|
||||
let res = await fetch(`/api/v2/servers/${serverId}`, {
|
||||
method: 'PATCH',
|
||||
headers: {
|
||||
'X-XSRFToken': token
|
||||
},
|
||||
body: formDataJsonString,
|
||||
});
|
||||
let responseData = await res.json();
|
||||
if (responseData.status === "ok") {
|
||||
window.location.reload();
|
||||
} else {
|
||||
|
||||
bootbox.alert({
|
||||
title: responseData.error,
|
||||
message: responseData.error_data
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
|
@ -37,15 +37,12 @@
|
||||
<div class="row">
|
||||
<div class="col-md-8 col-sm-8">
|
||||
{% if data['new_schedule'] == True %}
|
||||
<form class="forms-sample" method="post"
|
||||
<form class="forms-sample" method="post" id="new_schedule_form"
|
||||
action="/panel/new_schedule?id={{ data['server_stats']['server_id']['server_id'] }}">
|
||||
{% else %}
|
||||
<form class="forms-sample" method="post"
|
||||
<form class="forms-sample" method="post" id="schedule_form"
|
||||
action="/panel/edit_schedule?id={{ data['server_stats']['server_id']['server_id'] }}&sch_id={{ data['schedule']['schedule_id'] }}">
|
||||
{% end %}
|
||||
{% raw xsrf_form_html() %}
|
||||
<input type="hidden" name="id" value="{{ data['server_stats']['server_id']['server_id'] }}">
|
||||
<input type="hidden" name="subpage" value="config">
|
||||
|
||||
<div class="form-group">
|
||||
<label for="name">{{ translate('serverSchedules', 'name' , data['lang']) }}</label>
|
||||
@ -89,7 +86,7 @@
|
||||
class="text-muted ml-1"> - {{ translate('serverScheduleConfig', 'interval-explain' ,
|
||||
data['lang']) }}</small> </label>
|
||||
<input type="number" class="form-control" name="interval" id="interval"
|
||||
value="{{ data['schedule']['interval'] }}" placeholder="Interval" required>
|
||||
value="{{ data['schedule']['interval'] }}" placeholder="Interval" required min="1">
|
||||
<br>
|
||||
<br>
|
||||
<select id="interval_type" onchange="ifDays(this);" name="interval_type"
|
||||
@ -108,7 +105,7 @@
|
||||
<label for="time">{{ translate('serverScheduleConfig', 'time' , data['lang']) }} <small
|
||||
class="text-muted ml-1"> - {{ translate('serverScheduleConfig', 'time-explain' ,
|
||||
data['lang']) }}</small> </label>
|
||||
<input type="time" class="form-control" name="time" id="time"
|
||||
<input type="time" class="form-control" name="start_time" id="time"
|
||||
value="{{ data['schedule']['time'] }}" placeholder="Time" required>
|
||||
</div>
|
||||
</div>
|
||||
@ -127,7 +124,7 @@
|
||||
<label for="cron">{{ translate('serverScheduleConfig', 'cron' , data['lang']) }} <small
|
||||
class="text-muted ml-1"> - {{ translate('serverScheduleConfig', 'cron-explain' , data['lang'])
|
||||
}}</small> </label>
|
||||
<input type="input" class="form-control" name="cron" id="cron"
|
||||
<input type="input" class="form-control" name="cron_string" id="cron"
|
||||
value="{{ data['schedule']['cron_string'] }}" placeholder="* * * * *">
|
||||
</div>
|
||||
</div>
|
||||
@ -234,8 +231,124 @@
|
||||
return r ? r[1] : undefined;
|
||||
}
|
||||
|
||||
function replacer(key, value) {
|
||||
if (key != "start_time" && key != "cron_string" && key != "interval_type") {
|
||||
if (typeof value == "boolean") {
|
||||
return value
|
||||
}
|
||||
console.log(key)
|
||||
if (key === "interval" && value === ""){
|
||||
return 0;
|
||||
}
|
||||
if (key === "command" && typeof(value === "integer")){
|
||||
return value.toString();
|
||||
}else {
|
||||
return (isNaN(value) ? value : +value);
|
||||
}
|
||||
} else {
|
||||
if (value === "" && key == "start_time"){
|
||||
return "00:00";
|
||||
}else{
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const serverId = new URLSearchParams(document.location.search).get('id');
|
||||
const schId = new URLSearchParams(document.location.search).get('sch_id');
|
||||
$(document).ready(function () {
|
||||
console.log("ready!");
|
||||
$("#new_schedule_form").on("submit", async function (e) {
|
||||
e.preventDefault();
|
||||
var token = getCookie("_xsrf")
|
||||
let schForm = document.getElementById("new_schedule_form");
|
||||
|
||||
let formData = new FormData(schForm);
|
||||
formData.delete("difficulty");
|
||||
//Create an object from the form data entries
|
||||
let formDataObject = Object.fromEntries(formData.entries());
|
||||
//We need to make sure these are sent regardless of whether or not they're checked
|
||||
formDataObject.enabled = $("#enabled").prop('checked');
|
||||
formDataObject.one_time = $("#one_time").prop('checked');
|
||||
if ($("#difficulty").val() == "reaction"){
|
||||
formDataObject.interval_type = "reaction";
|
||||
}
|
||||
if ($("#action").val() != "command"){
|
||||
formDataObject.command = formDataObject.action + "_server";
|
||||
}
|
||||
if (formDataObject.cron_string != ""){
|
||||
formDataObject.interval_type = '';
|
||||
}
|
||||
console.log(formDataObject);
|
||||
// Format the plain form data as JSON
|
||||
let formDataJsonString = JSON.stringify(formDataObject, replacer);
|
||||
|
||||
let res = await fetch(`/api/v2/servers/${serverId}/tasks/`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'X-XSRFToken': token,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: formDataJsonString,
|
||||
});
|
||||
let responseData = await res.json();
|
||||
if (responseData.status === "ok") {
|
||||
window.location.href = `/panel/server_detail?id=${serverId}&subpage=schedules`;
|
||||
} else {
|
||||
|
||||
bootbox.alert({
|
||||
title: responseData.status,
|
||||
message: responseData.error
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
$("#schedule_form").on("submit", async function (e) {
|
||||
e.preventDefault();
|
||||
var token = getCookie("_xsrf")
|
||||
let schForm = document.getElementById("schedule_form");
|
||||
|
||||
let formData = new FormData(schForm);
|
||||
formData.delete("difficulty");
|
||||
//Create an object from the form data entries
|
||||
let formDataObject = Object.fromEntries(formData.entries());
|
||||
//We need to make sure these are sent regardless of whether or not they're checked
|
||||
formDataObject.enabled = $("#enabled").prop('checked');
|
||||
formDataObject.one_time = $("#one_time").prop('checked');
|
||||
if ($("#difficulty").val() == "reaction"){
|
||||
formDataObject.interval_type = "reaction";
|
||||
}
|
||||
if ($("#action").val() != "command"){
|
||||
formDataObject.command = formDataObject.action + "_server";
|
||||
}
|
||||
if (formDataObject.cron_string != ""){
|
||||
formDataObject.interval_type = '';
|
||||
}
|
||||
console.log(formDataObject);
|
||||
// Format the plain form data as JSON
|
||||
let formDataJsonString = JSON.stringify(formDataObject, replacer);
|
||||
|
||||
console.log(formDataJsonString);
|
||||
|
||||
let res = await fetch(`/api/v2/servers/${serverId}/tasks/${schId}`, {
|
||||
method: 'PATCH',
|
||||
headers: {
|
||||
'X-XSRFToken': token,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: formDataJsonString,
|
||||
});
|
||||
let responseData = await res.json();
|
||||
if (responseData.status === "ok") {
|
||||
window.location.href = `/panel/server_detail?id=${serverId}&subpage=schedules`;
|
||||
} else {
|
||||
|
||||
bootbox.alert({
|
||||
title: responseData.error,
|
||||
message: responseData.error_data
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@ -265,6 +378,7 @@
|
||||
document.getElementById("parent").required = true;
|
||||
document.getElementById("interval").required = false;
|
||||
document.getElementById("time").required = false;
|
||||
$("#cron").val("");
|
||||
}
|
||||
else {
|
||||
document.getElementById("ifAdvanced").style.display = "none";
|
||||
@ -274,6 +388,7 @@
|
||||
document.getElementById("parent").required = false;
|
||||
document.getElementById("interval").required = true;
|
||||
document.getElementById("time").required = true;
|
||||
$("#cron").val("");
|
||||
}
|
||||
}
|
||||
function ifDays() {
|
||||
@ -286,22 +401,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
function del_task(sch_id, id) {
|
||||
var token = getCookie("_xsrf")
|
||||
|
||||
$.ajax({
|
||||
type: "DELETE",
|
||||
headers: { 'X-XSRFToken': token },
|
||||
url: '/ajax/del_task?server_id=' + id + '&schedule_id=' + sch_id,
|
||||
data: {
|
||||
schedule_id: sch_id,
|
||||
id: id
|
||||
},
|
||||
success: function (data) {
|
||||
location.reload();
|
||||
},
|
||||
});
|
||||
}
|
||||
function startup() {
|
||||
try {
|
||||
document.getElementById("{{ data['schedule']['interval_type'] }}").setAttribute('selected', true);
|
||||
|
@ -47,18 +47,14 @@
|
||||
<h4 class="card-title"><i class="fas fa-calendar"></i> {{ translate('serverSchedules',
|
||||
'scheduledTasks', data['lang']) }} </h4>
|
||||
{% if data['user_data']['hints'] %}
|
||||
<span class="too_small" title="{{ translate('serverSchedules', 'cannotSee', data['lang']) }}" ,
|
||||
data-content="{{ translate('serverSchedules', 'cannotSeeOnMobile', data['lang']) }}" ,
|
||||
data-placement="bottom"></span>
|
||||
<span class="too_small" title="{{ translate('serverSchedules', 'cannotSee', data['lang']) }}" , data-content="{{ translate('serverSchedules', 'cannotSeeOnMobile', data['lang']) }}" , data-placement="bottom"></span>
|
||||
{% end %}
|
||||
<div><button
|
||||
onclick="location.href=`/panel/add_schedule?id={{ data['server_stats']['server_id']['server_id'] }}`"
|
||||
class="btn btn-info">{{ translate('serverSchedules', 'create', data['lang']) }}<i
|
||||
class="fas fa-pencil-alt"></i></button></div>
|
||||
<div>
|
||||
<button onclick="location.href=`/panel/add_schedule?id={{ data['server_stats']['server_id']['server_id'] }}`" class="btn btn-info">{{ translate('serverSchedules', 'create', data['lang']) }}<i class="fas fa-pencil-alt"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<table class="table table-hover d-none d-lg-block responsive-table" id="schedule_table" width="100%"
|
||||
style="table-layout:fixed;">
|
||||
<table class="table table-hover d-none d-lg-block responsive-table" id="schedule_table" width="100%" style="table-layout:fixed;">
|
||||
<thead>
|
||||
<tr class="rounded">
|
||||
<th style="width: 2%; min-width: 10px;">{{ translate('serverSchedules', 'name', data['lang']) }}
|
||||
@ -87,10 +83,10 @@
|
||||
<p>{{schedule.action}}</p>
|
||||
</td>
|
||||
<td id="{{schedule.command}}" class="action" style="overflow: scroll; max-width: 30px;">
|
||||
<p>{{schedule.command}}</p>
|
||||
<p style="overflow: scroll;" class="no-scroll">{{schedule.command}}</p>
|
||||
</td>
|
||||
<td id="{{schedule.interval}}" class="action">
|
||||
{% if schedule.interval != '' %}
|
||||
{% if schedule.interval_type != '' and schedule.interval_type != 'reaction' %}
|
||||
<p>{{ translate('serverSchedules', 'every', data['lang']) }}</p>
|
||||
<p>{{schedule.interval}} {{schedule.interval_type}}</p>
|
||||
{% elif schedule.interval_type == 'reaction' %}
|
||||
@ -105,14 +101,10 @@
|
||||
<p>{{schedule.next_run}}</p>
|
||||
</td>
|
||||
<td id="{{schedule.enabled}}" class="action">
|
||||
<input style="width: 10px !important;" type="checkbox" class="schedule-enabled-toggle"
|
||||
data-schedule-id="{{schedule.schedule_id}}"
|
||||
data-schedule-enabled="{{ 'true' if schedule.enabled else 'false' }}">
|
||||
<input style="width: 10px !important;" type="checkbox" class="schedule-enabled-toggle" data-schedule-id="{{schedule.schedule_id}}" data-schedule-enabled="{{ 'true' if schedule.enabled else 'false' }}">
|
||||
</td>
|
||||
<td id="{{schedule.action}}" class="action">
|
||||
<button
|
||||
onclick="window.location.href='/panel/edit_schedule?id={{ data['server_stats']['server_id']['server_id'] }}&sch_id={{schedule.schedule_id}}'"
|
||||
class="btn btn-info">
|
||||
<button onclick="window.location.href='/panel/edit_schedule?id={{ data['server_stats']['server_id']['server_id'] }}&sch_id={{schedule.schedule_id}}'" class="btn btn-info">
|
||||
<i class="fas fa-pencil-alt"></i>
|
||||
</button>
|
||||
<br>
|
||||
@ -126,8 +118,7 @@
|
||||
</tbody>
|
||||
</table>
|
||||
<hr />
|
||||
<table class="table table-hover d-block d-lg-none" id="mini_schedule_table" width="100%"
|
||||
style="table-layout:fixed;">
|
||||
<table class="table table-hover d-block d-lg-none" id="mini_schedule_table" width="100%" style="table-layout:fixed;">
|
||||
<thead>
|
||||
<tr class="rounded">
|
||||
<th style="width: 25%; min-width: 50px;">{{ translate('serverSchedules', 'action', data['lang'])
|
||||
@ -145,7 +136,7 @@
|
||||
<p>{{schedule.action}}</p>
|
||||
</td>
|
||||
<td id="{{schedule.command}}" class="action" style="overflow: scroll; max-width: 30px;">
|
||||
<p>{{schedule.command}}</p>
|
||||
<p style="overflow: scroll;">{{schedule.command}}</p>
|
||||
</td>
|
||||
<td id="{{schedule.enabled}}" class="action">
|
||||
{% if schedule.enabled %}
|
||||
@ -160,8 +151,7 @@
|
||||
</td>
|
||||
</tr>
|
||||
<!-- Modal -->
|
||||
<div class="modal fade" id="task_details_{{schedule.schedule_id}}" tabindex="-1" role="dialog"
|
||||
aria-labelledby="exampleModalLabel" aria-hidden="true">
|
||||
<div class="modal fade" id="task_details_{{schedule.schedule_id}}" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
@ -208,19 +198,14 @@
|
||||
<p>zzzzzzz</p>
|
||||
{% end %}
|
||||
</li>
|
||||
<li id="{{schedule.enabled}}" class="action"
|
||||
style="border-top: .1em solid gray; border-bottom: .1em solid gray">
|
||||
<li id="{{schedule.enabled}}" class="action" style="border-top: .1em solid gray; border-bottom: .1em solid gray">
|
||||
<h4>{{ translate('serverSchedules', 'enabled', data['lang']) }}</h4>
|
||||
<input type="checkbox" class="schedule-enabled-toggle"
|
||||
data-schedule-id="{{schedule.schedule_id}}"
|
||||
data-schedule-enabled="{{ 'true' if schedule.enabled else 'false' }}">
|
||||
<input type="checkbox" class="schedule-enabled-toggle" data-schedule-id="{{schedule.schedule_id}}" data-schedule-enabled="{{ 'true' if schedule.enabled else 'false' }}">
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button
|
||||
onclick="window.location.href='/panel/edit_schedule?id={{ data['server_stats']['server_id']['server_id'] }}&sch_id={{schedule.schedule_id}}'"
|
||||
class="btn btn-info">
|
||||
<button onclick="window.location.href='/panel/edit_schedule?id={{ data['server_stats']['server_id']['server_id'] }}&sch_id={{schedule.schedule_id}}'" class="btn btn-info">
|
||||
<i class="fas fa-pencil-alt"></i> {{ translate('serverSchedules', 'edit', data['lang'])
|
||||
}}
|
||||
</button>
|
||||
@ -381,39 +366,6 @@
|
||||
console.log("ready!");
|
||||
|
||||
});
|
||||
|
||||
function yesnoCheck(that) {
|
||||
if (that.value == "command") {
|
||||
document.getElementById("ifYes").style.display = "block";
|
||||
document.getElementById("command").required = true;
|
||||
} else {
|
||||
document.getElementById("ifYes").style.display = "none";
|
||||
document.getElementById("command").required = false;
|
||||
}
|
||||
}
|
||||
function basicAdvanced(that) {
|
||||
if (that.value == "advanced") {
|
||||
document.getElementById("ifAdvanced").style.display = "block";
|
||||
document.getElementById("ifBasic").style.display = "none";
|
||||
document.getElementById("interval").required = false;
|
||||
document.getElementById("time").required = false;
|
||||
} else {
|
||||
document.getElementById("ifAdvanced").style.display = "none";
|
||||
document.getElementById("ifBasic").style.display = "block";
|
||||
document.getElementById("interval").required = true;
|
||||
document.getElementById("time").required = true;
|
||||
}
|
||||
}
|
||||
function ifDays(that) {
|
||||
if (that.value == "days") {
|
||||
document.getElementById("ifDays").style.display = "block";
|
||||
document.getElementById("time").required = true;
|
||||
} else {
|
||||
document.getElementById("ifDays").style.display = "none";
|
||||
document.getElementById("time").required = false;
|
||||
}
|
||||
}
|
||||
|
||||
$(".del_button").click(function () {
|
||||
var sch_id = $(this).data('sch');
|
||||
|
||||
@ -440,21 +392,19 @@
|
||||
});
|
||||
});
|
||||
|
||||
function del_task(sch_id, id) {
|
||||
async function del_task(sch_id, id) {
|
||||
var token = getCookie("_xsrf")
|
||||
|
||||
$.ajax({
|
||||
type: "DELETE",
|
||||
headers: { 'X-XSRFToken': token },
|
||||
url: '/ajax/del_task?server_id=' + id + '&schedule_id=' + sch_id,
|
||||
data: {
|
||||
schedule_id: sch_id,
|
||||
id: id
|
||||
},
|
||||
success: function (data) {
|
||||
location.reload();
|
||||
let res = await fetch(`/api/v2/servers/${id}/tasks/${sch_id}`, {
|
||||
method: 'DELETE',
|
||||
headers: {
|
||||
'token': token,
|
||||
},
|
||||
});
|
||||
let responseData = await res;
|
||||
if (responseData.statusText === "OK") {
|
||||
window.location.reload();
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
@ -41,10 +41,9 @@
|
||||
</span>
|
||||
|
||||
<div class="col-md-12">
|
||||
<button id="to-bottom" style="visibility: hidden; float: right;" class="btn btn-outline-success">{{
|
||||
<button id="to-bottom" style="visibility: hidden; float: right;" class="btn btn-outline-success" hidden>{{
|
||||
translate('serverDetails', 'reset', data['lang']) }}</button>
|
||||
<br />
|
||||
<br />
|
||||
|
||||
<div class="input-group">
|
||||
<div id="virt_console" class=""
|
||||
style="width: 100%; font-size: .8em; padding: 5px 10px; border: 1px solid var(--outline); background-color:var(--card-banner-bg);height:500px; overflow: scroll;">
|
||||
@ -151,6 +150,8 @@
|
||||
/* IE and Edge */
|
||||
scrollbar-width: none;
|
||||
/* Firefox */
|
||||
font-family:Consolas,Monaco,Lucida Console,Liberation Mono,DejaVu Sans Mono,Bitstream Vera Sans Mono,Courier New, monospace;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
</style>
|
||||
<!-- content-wrapper ends -->
|
||||
@ -179,7 +180,7 @@
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
headers: { 'X-XSRFToken': token },
|
||||
url: '/server/command?command=' + command + '&id=' + serverId,
|
||||
url: `/api/v2/servers/${serverId}/action/${command}`,
|
||||
success: function (data) {
|
||||
console.log("got response:");
|
||||
console.log(data);
|
||||
@ -311,12 +312,12 @@
|
||||
formdata.append('command', serverCommand)
|
||||
|
||||
console.log('sending command: ' + serverCommand)
|
||||
let res = await fetch("/ajax/send_command?id=" + serverId, {
|
||||
let res = await fetch(`/api/v2/servers/${serverId}/stdin`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'X-XSRFToken': token
|
||||
},
|
||||
body: formdata,
|
||||
body: serverCommand,
|
||||
});
|
||||
|
||||
let responseData = await res.text();
|
||||
@ -354,9 +355,11 @@
|
||||
const elem = $(e.currentTarget);
|
||||
if (Math.round(elem[0].scrollHeight - elem.scrollTop()) <= elem.outerHeight()) {
|
||||
document.getElementById("to-bottom").style.visibility = "hidden";
|
||||
document.getElementById("to-bottom").hidden = true;
|
||||
scrolled = false;
|
||||
} else {
|
||||
document.getElementById("to-bottom").style.visibility = "visible";
|
||||
document.getElementById("to-bottom").hidden = false;
|
||||
scrolled = true;
|
||||
}
|
||||
}
|
||||
|
@ -13,14 +13,14 @@
|
||||
<div class="row page-title-header">
|
||||
<div class="col-12">
|
||||
<div class="page-header">
|
||||
<h4 class="page-title">Wiki</h4>
|
||||
<h4 class="page-title">{{ translate('sidebar', 'documentation', data['lang']) }}</h4>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12 grid-margin">
|
||||
<iframe src="https://wiki.craftycontrol.com" width=100% height=2200px title="crafty's wiki"></iframe>
|
||||
<iframe src="https://docs.craftycontrol.com/" width=100% height=1100px title="crafty's docs"></iframe>
|
||||
</div>
|
||||
|
||||
|
||||
|
@ -12,6 +12,14 @@
|
||||
<link rel="stylesheet" href="/static/assets/vendors/ti-icons/css/themify-icons.css">
|
||||
<link rel="stylesheet" href="/static/assets/vendors/typicons/typicons.css">
|
||||
<link rel="stylesheet" href="/static/assets/vendors/css/vendor.bundle.base.css">
|
||||
<link rel="manifest" href="/static/assets/crafty.webmanifest">
|
||||
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<meta name="mobile-web-app-capable" content="yes" />
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black">
|
||||
<meta name="apple-mobile-web-app-title" content="Crafty">
|
||||
<link rel="apple-touch-icon" href="../static/assets/images/Crafty_4-0.png">
|
||||
|
||||
<!-- endinject -->
|
||||
<!-- Plugin css for this page -->
|
||||
<!-- End Plugin css for this page -->
|
||||
@ -24,7 +32,7 @@
|
||||
<style>
|
||||
.auth.auth-bg-1 {
|
||||
background: url("../../static/assets/images/auth/{% raw data['background'] %}"),
|
||||
url("../../static/assets/images/auth/login-1.jpg");
|
||||
url("/static/assets/images/auth/login_1.jpg");
|
||||
background-size: cover;
|
||||
}
|
||||
</style>
|
||||
|
@ -12,6 +12,14 @@
|
||||
<link rel="stylesheet" href="/static/assets/vendors/ti-icons/css/themify-icons.css">
|
||||
<link rel="stylesheet" href="/static/assets/vendors/typicons/typicons.css">
|
||||
<link rel="stylesheet" href="/static/assets/vendors/css/vendor.bundle.base.css">
|
||||
<link rel="manifest" href="/static/assets/crafty.webmanifest">
|
||||
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<meta name="mobile-web-app-capable" content="yes" />
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black">
|
||||
<meta name="apple-mobile-web-app-title" content="Crafty">
|
||||
<link rel="apple-touch-icon" href="../static/assets/images/Crafty_4-0.png">
|
||||
|
||||
<!-- endinject -->
|
||||
<!-- Plugin css for this page -->
|
||||
<!-- End Plugin css for this page -->
|
||||
@ -24,7 +32,7 @@
|
||||
<style>
|
||||
.auth.auth-bg-1 {
|
||||
background: url("../../static/assets/images/auth/{% raw data['background'] %}"),
|
||||
url("../../static/assets/images/auth/login-1.jpg");
|
||||
url("/static/assets/images/auth/login_1.jpg");
|
||||
background-size: cover;
|
||||
}
|
||||
</style>
|
||||
|
@ -12,6 +12,13 @@
|
||||
<link rel="stylesheet" href="/static/assets/vendors/ti-icons/css/themify-icons.css">
|
||||
<link rel="stylesheet" href="/static/assets/vendors/typicons/typicons.css">
|
||||
<link rel="stylesheet" href="/static/assets/vendors/css/vendor.bundle.base.css">
|
||||
<link rel="manifest" href="/static/assets/crafty.webmanifest">
|
||||
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<meta name="mobile-web-app-capable" content="yes" />
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black">
|
||||
<!-- <meta name="apple-mobile-web-app-title" content="Crafty Controller 4"> -->
|
||||
<link rel="apple-touch-icon" href="../static/assets/images/Crafty_4-0.png">
|
||||
<!-- endinject -->
|
||||
<!-- Plugin css for this page -->
|
||||
<!-- End Plugin css for this page -->
|
||||
@ -24,7 +31,7 @@
|
||||
<style>
|
||||
.auth.auth-bg-1 {
|
||||
background: url("../../static/assets/images/auth/{% raw data['background'] %}"),
|
||||
url("../../static/assets/images/auth/login-1.jpg");
|
||||
url("/static/assets/images/auth/login_1.jpg");
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
}
|
||||
@ -113,6 +120,11 @@
|
||||
<span class="text-small font-weight-semibold"><a href="https://craftycontrol.com/">Crafty Control
|
||||
{{data['version'] }}</a> </span>
|
||||
</div>
|
||||
|
||||
<div class="text-block text-center my-3">
|
||||
<a href="/status" class="text-small forgot-password">{{ translate('login', 'viewStatus',
|
||||
data['lang']) }}</a>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
@ -140,7 +152,15 @@
|
||||
let login_opacity_div = document.getElementById('login_opacity');
|
||||
let opacity = login_opacity_div.getAttribute('data-value');
|
||||
document.getElementById('login-form-background').style.background = 'rgb(34, 36, 55, ' + (opacity / 100) + ')';
|
||||
//Register Service worker for mobile app
|
||||
if ('serviceWorker' in navigator) {
|
||||
navigator.serviceWorker.register('/static/assets/js/shared/service-worker.js', {scope: '/'})
|
||||
.then(function (registration) {
|
||||
console.error('Service Worker Registered');
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
</script>
|
||||
</body>
|
||||
|
||||
|
85
app/frontend/templates/public/offline.html
Normal file
85
app/frontend/templates/public/offline.html
Normal file
@ -0,0 +1,85 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<!-- Required meta tags -->
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<title>Crafty Controller</title>
|
||||
<!-- plugins:css -->
|
||||
<link rel="stylesheet" href="/static/assets/vendors/mdi/css/materialdesignicons.min.css">
|
||||
<link rel="stylesheet" href="/static/assets/vendors/flag-icon-css/css/flag-icon.min.css">
|
||||
<link rel="stylesheet" href="/static/assets/vendors/ti-icons/css/themify-icons.css">
|
||||
<link rel="stylesheet" href="/static/assets/vendors/typicons/typicons.css">
|
||||
<link rel="stylesheet" href="/static/assets/vendors/css/vendor.bundle.base.css">
|
||||
<link rel="manifest" href="/static/assets/crafty.webmanifest">
|
||||
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<meta name="mobile-web-app-capable" content="yes" />
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black">
|
||||
<meta name="apple-mobile-web-app-title" content="Crafty">
|
||||
<link rel="apple-touch-icon" href="../static/assets/images/Crafty_4-0.png">
|
||||
|
||||
<!-- endinject -->
|
||||
<!-- Plugin css for this page -->
|
||||
<!-- End Plugin css for this page -->
|
||||
<!-- Layout styles -->
|
||||
<link rel="stylesheet" href="/static/assets/css/dark/style.css">
|
||||
<!-- End Layout styles -->
|
||||
<link rel="shortcut icon" type="image/svg+xml" href="/static/assets/images/logo_small.svg">
|
||||
<link rel="alternate icon" href="/static/assets/images/favicon.png" />
|
||||
</head>
|
||||
<style>
|
||||
.auth.auth-bg-1 {
|
||||
background: url("../../static/assets/images/auth/{% raw data['background'] %}"),
|
||||
url("/static/assets/images/auth/login_1.jpg");
|
||||
background-size: cover;
|
||||
}
|
||||
</style>
|
||||
|
||||
<body class="dark-theme">
|
||||
<div class="container-scroller">
|
||||
<div class="container-fluid page-body-wrapper full-page-wrapper">
|
||||
<div class="content-wrapper d-flex align-items-center auth auth-bg-1 theme-one">
|
||||
<div class="row w-100">
|
||||
<div class="col-lg-4 mx-auto">
|
||||
|
||||
<div class="auto-form-wrapper">
|
||||
<div class="text-center">
|
||||
<img src="/static/assets/images/logo_long.svg"><br /><br />
|
||||
<div class="col-sm-12 grid-margin stretch-card">
|
||||
<div class="card card-statistics social-card facebook-card card-colored">
|
||||
<div class="card-body">
|
||||
<h4 class="platform-name mb-3 mt-4 font-weight-semibold user-name">{{ translate('offline', 'offline', data['lang']) }}</h4>
|
||||
<h5 class="headline font-weight-medium"></h5>
|
||||
<p class="mb-2 comment font-weight-light">
|
||||
{{ translate('offline', 'pleaseConnect', data['lang']) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- content-wrapper ends -->
|
||||
</div>
|
||||
<!-- page-body-wrapper ends -->
|
||||
</div>
|
||||
<!-- container-scroller -->
|
||||
<!-- plugins:js -->
|
||||
<script src="/static/assets/vendors/js/vendor.bundle.base.js"></script>
|
||||
<!-- endinject -->
|
||||
<!-- inject:js -->
|
||||
<script src="/static/assets/js/shared/off-canvas.js"></script>
|
||||
<script src="/static/assets/js/shared/hoverable-collapse.js"></script>
|
||||
<script src="/static/assets/js/shared/misc.js"></script>
|
||||
<script src="/static/assets/js/shared/settings.js"></script>
|
||||
<script src="/static/assets/js/shared/todolist.js"></script>
|
||||
<!-- endinject -->
|
||||
</body>
|
||||
|
||||
</html>
|
@ -10,7 +10,7 @@
|
||||
<style>
|
||||
.auth.auth-bg-1 {
|
||||
background: url("../../static/assets/images/auth/{% raw data['background'] %}"),
|
||||
url("../../static/assets/images/auth/login-1.jpg");
|
||||
url("/static/assets/images/auth/login_1.jpg");
|
||||
background-size: cover;
|
||||
}
|
||||
</style>
|
||||
@ -89,7 +89,7 @@
|
||||
</div>
|
||||
<!-- View for Small screen -->
|
||||
<div class="row justify-content-center align-items-sm-center">
|
||||
<div class="content-wrapper login-modal d-sm-none d-block">
|
||||
<div class="content-wrapper login-modal d-sm-none d-block" style="background-color: var(--dropdown-bg);">
|
||||
<img src="/static/assets/images/logo_long.png" style='width: 100%;'>
|
||||
<hr />
|
||||
{% if data['running'] != 0 %}
|
||||
|
@ -14,6 +14,13 @@
|
||||
<link rel="stylesheet" href="/static/assets/vendors/typicons/typicons.css">
|
||||
<link rel="stylesheet" href="/static/assets/vendors/css/vendor.bundle.base.css">
|
||||
<link rel="stylesheet" href="/static/assets/vendors/fontawesome6/css/all.css">
|
||||
<link rel="manifest" href="/static/assets/crafty.webmanifest">
|
||||
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<meta name="mobile-web-app-capable" content="yes" />
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black">
|
||||
<meta name="apple-mobile-web-app-title" content="Crafty">
|
||||
<link rel="apple-touch-icon" href="../static/assets/images/Crafty_4-0.png">
|
||||
<!-- endinject -->
|
||||
<!-- Plugin css for this page -->
|
||||
<!-- End Plugin css for this page -->
|
||||
@ -98,7 +105,7 @@
|
||||
usingWebSockets = false;
|
||||
}
|
||||
// {% else %}
|
||||
let usingWebSockets = false;
|
||||
usingWebSockets = false;
|
||||
warn('WebSockets are not supported in Crafty if not using the https protocol')
|
||||
var webSocket;
|
||||
// {% end%}
|
||||
@ -106,6 +113,21 @@
|
||||
</script>
|
||||
{% block js %}
|
||||
<!-- Custom js for this page -->
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
let login_opacity_div = document.getElementById('login_opacity');
|
||||
let opacity = login_opacity_div.getAttribute('data-value');
|
||||
document.getElementById('login-form-background').style.background = 'rgb(34, 36, 55, ' + (opacity / 100) + ')';
|
||||
//Register Service worker for mobile app
|
||||
if ('serviceWorker' in navigator) {
|
||||
navigator.serviceWorker.register('/static/assets/js/shared/service-worker.js', {scope: '/'})
|
||||
.then(function (registration) {
|
||||
console.error('Service Worker Registered');
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
</script>
|
||||
<!-- End custom js for this page -->
|
||||
{% end %}
|
||||
|
||||
|
@ -31,36 +31,54 @@
|
||||
</ul>
|
||||
<div class="d-none" id="overlay" onclick="hide(event)"></div>
|
||||
<div class="row">
|
||||
{% if data['online'] %}
|
||||
<div class="col-sm-6 grid-margin stretch-card">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
|
||||
<h4>{{ translate('serverWizard', 'newServer', data['lang']) }}</h4>
|
||||
<br />
|
||||
<p class="card-description">
|
||||
|
||||
<form method="post" name="create_server" class="server-wizard" onSubmit="wait_msg()">
|
||||
{% if data["server_api"] and data["online"] %}
|
||||
<fieldset>
|
||||
{% else %}
|
||||
<fieldset disabled="disabled">
|
||||
<style>
|
||||
.api-alert{
|
||||
position:absolute;
|
||||
top:-5px;
|
||||
left:0;
|
||||
font-size: 50px !important;
|
||||
color:#fff;
|
||||
background:rgb(127, 133, 133);
|
||||
opacity:.4;
|
||||
width:100%;
|
||||
height:100%;
|
||||
z-index: 100;
|
||||
}
|
||||
.api-alert p {
|
||||
margin: 0;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
text-align: center;
|
||||
font-size: 20px;
|
||||
-ms-transform: translate(-50%, -50%);
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
</style>
|
||||
{% end %}
|
||||
{% raw xsrf_form_html() %}
|
||||
<div class="row">
|
||||
|
||||
<div class="col-sm-12 col-md-12">
|
||||
<div class="form-group">
|
||||
<label for="server_name">{{ translate('serverWizard', 'serverName', data['lang']) }}</label>
|
||||
<input type="text" class="form-control" id="server_name" name="server_name"
|
||||
placeholder="{{ translate('serverWizard', 'myNewServer', data['lang']) }}" required>
|
||||
</div>
|
||||
<input type="text" class="form-control" id="server_name" name="server_name" placeholder="{{ translate('serverWizard', 'myNewServer', data['lang']) }}" required>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="col-sm-12">
|
||||
<div class="form-group">
|
||||
<div id="accordion-1">
|
||||
<div class="card">
|
||||
<div class="card-header p-2" id="Role-1">
|
||||
<p class="mb-0 p-0" data-toggle="collapse" data-target="#collapseRole-1" aria-expanded="true"
|
||||
aria-controls="collapseRole-1">
|
||||
<p class="mb-0 p-0" data-toggle="collapse" data-target="#collapseRole-1" aria-expanded="true" aria-controls="collapseRole-1">
|
||||
<i class="fas fa-chevron-down"></i> {{ translate('serverWizard', 'addRole', data['lang']) }}
|
||||
<small style="text-transform: none;"> - {{ translate('serverWizard', 'autoCreate',
|
||||
data['lang']) }}</small>
|
||||
@ -70,8 +88,7 @@
|
||||
<div class="card-body scroll">
|
||||
<div class="form-group">
|
||||
{% for r in data['roles'] %}
|
||||
<span class="d-block menu-option"><label><input name="{{ r['role_id'] }}"
|
||||
type="checkbox">
|
||||
<span class="d-block menu-option"><label><input name="{{ r['role_id'] }}" type="checkbox">
|
||||
{{ r['role_name'].capitalize() }}</label></span>
|
||||
{% end %}
|
||||
</div>
|
||||
@ -80,81 +97,63 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button onclick="eula_confirm()" type="button" class="btn btn-primary mr-2">{{ translate('serverWizard',
|
||||
'buildServer',
|
||||
data['lang']) }}</button>
|
||||
<button type="reset" class="btn btn-danger mr-2">{{ translate('serverWizard', 'resetForm', data['lang'])
|
||||
}}</button>
|
||||
</fieldset>
|
||||
{% if not data["server_api"] and data["online"] %}
|
||||
<div class="api-alert" style="position: absolute; top: -5px; z-index: 100; opacity: .99;">
|
||||
<p style="color: white !important;"><i class="fas fa-exclamation-triangle" style="color: red;"></i> {{ translate('error', 'bedrockError', data['lang']) }}<a style="color: red;"; href="https://status.craftycontrol.com/status/craftycontrol"
|
||||
target="_blank"> {{ translate('error', 'craftyStatus', data['lang']) }}</a>
|
||||
{{ translate('error', 'serverJars2', data['lang']) }}</p></div>
|
||||
{% end %}
|
||||
{% if not data["online"] %}
|
||||
<div class="api-alert" style="position: absolute; top: -5px; z-index: 100; opacity: .99;">
|
||||
<p style="color: white !important;"><i class="fas fa-exclamation-triangle" style="color: red;"></i> {{ translate('error', 'noInternet', data['lang']) }}</p></div>
|
||||
{% end %}
|
||||
</div>
|
||||
</form>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
{% end %}
|
||||
<div class="col-sm-6 grid-margin stretch-card">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
|
||||
<h4>{{ translate('serverWizard', 'importServer', data['lang']) }}</h4>
|
||||
<br />
|
||||
<p class="card-description">
|
||||
|
||||
<form method="post" class="server-wizard" onSubmit="wait_msg(true)">
|
||||
{% raw xsrf_form_html() %}
|
||||
<input type="hidden" value="import_jar" name="create_type">
|
||||
<div class="row">
|
||||
|
||||
<div class="col-sm-12">
|
||||
<div class="form-group">
|
||||
<label for="server_name">{{ translate('serverWizard', 'serverName', data['lang']) }}</label>
|
||||
<input type="text" class="form-control" id="server_name" name="server_name" value=""
|
||||
placeholder="{{ translate('serverWizard', 'myNewServer', data['lang']) }}" required>
|
||||
<input type="text" class="form-control" id="server_name" name="server_name" value="" placeholder="{{ translate('serverWizard', 'myNewServer', data['lang']) }}" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-12">
|
||||
<div class="form-group">
|
||||
<label for="server">{{ translate('serverWizard', 'serverPath', data['lang']) }} <small>{{
|
||||
translate('serverWizard', 'absoluteServerPath', data['lang']) }}</small></label>
|
||||
<input type="text" class="form-control" id="server_path" name="server_path"
|
||||
placeholder="/var/opt/server" required>
|
||||
<input type="text" class="form-control" id="server_path" name="server_path" placeholder="/var/opt/server" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-12">
|
||||
<div class="form-group">
|
||||
<label for="server_jar">{{ translate('serverWizard', 'serverJar', data['lang']) }}</label>
|
||||
<input type="text" class="form-control" id="server_jar" name="server_jar" value=""
|
||||
placeholder="bedrock_server" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<input type="text" class="form-control" id="server_jar" name="server_jar" value="" placeholder="bedrock_server" required>
|
||||
</div>
|
||||
<br />
|
||||
<h4 class="card-title">{{ translate('serverWizard', 'quickSettings', data['lang']) }} <small
|
||||
style="text-transform: none;"> - {{ translate('serverWizard', 'quickSettingsDescription',
|
||||
<h4 class="card-title">{{ translate('serverWizard', 'quickSettings', data['lang']) }} <small style="text-transform: none;"> - {{ translate('serverWizard', 'quickSettingsDescription',
|
||||
data['lang']) }}</small></h4>
|
||||
<hr>
|
||||
<div class="row">
|
||||
|
||||
<div class="col-sm-12">
|
||||
<div class="form-group">
|
||||
<label for="port2">{{ translate('serverWizard', 'serverPort', data['lang']) }}
|
||||
<small></small></label>
|
||||
<input type="number" class="form-control" id="port2" name="port" value="19132" step="1" min="1"
|
||||
max="65535" required>
|
||||
<input type="number" class="form-control" id="port2" name="port" value="19132" step="1" min="1" max="65535" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-12">
|
||||
<div class="form-group">
|
||||
<div id="accordion-2">
|
||||
<div class="card">
|
||||
<div class="card-header p-2" id="Role-2">
|
||||
<p class="mb-0 p-0" data-toggle="collapse" data-target="#collapseRole-2" aria-expanded="true"
|
||||
aria-controls="collapseRole-2">
|
||||
<p class="mb-0 p-0" data-toggle="collapse" data-target="#collapseRole-2" aria-expanded="true" aria-controls="collapseRole-2">
|
||||
<i class="fas fa-chevron-down"></i> {{ translate('serverWizard', 'addRole', data['lang']) }}
|
||||
<small style="text-transform: none;"> - {{ translate('serverWizard', 'autoCreate',
|
||||
data['lang']) }}</small>
|
||||
@ -164,8 +163,7 @@
|
||||
<div class="card-body scroll">
|
||||
<div class="form-group">
|
||||
{% for r in data['roles'] %}
|
||||
<span class="d-block menu-option"><label><input name="{{ r['role_id'] }}"
|
||||
type="checkbox">
|
||||
<span class="d-block menu-option"><label><input name="{{ r['role_id'] }}" type="checkbox">
|
||||
{{ r['role_name'].capitalize() }}</label></span>
|
||||
{% end %}
|
||||
</div>
|
||||
@ -174,53 +172,35 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary mr-2">{{ translate('serverWizard', 'importServerButton',
|
||||
data['lang']) }}</button>
|
||||
<button type="reset" class="btn btn-danger mr-2">{{ translate('serverWizard', 'resetForm', data['lang'])
|
||||
}}</button>
|
||||
|
||||
</form>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-6 grid-margin stretch-card">
|
||||
<div class="col-md-6 grid-margin stretch-card">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
|
||||
<h4>{{ translate('serverWizard', 'importZip', data['lang']) }}</h4>
|
||||
<br />
|
||||
<p class="card-description">
|
||||
|
||||
<form name="zip" method="post" class="server-wizard" onSubmit="wait_msg(true)">
|
||||
{% raw xsrf_form_html() %}
|
||||
<input type="hidden" value="import_zip" name="create_type">
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-9">
|
||||
<div class="col-sm-12">
|
||||
<div class="form-group">
|
||||
<label for="server_name">{{ translate('serverWizard', 'serverName', data['lang']) }}</label>
|
||||
<input type="text" class="form-control" id="server_name" name="server_name" value=""
|
||||
placeholder="{{ translate('serverWizard', 'myNewServer', data['lang']) }}" required>
|
||||
</div>
|
||||
<input type="text" class="form-control" id="server_name" name="server_name" value="" placeholder="{{ translate('serverWizard', 'myNewServer', data['lang']) }}" required>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-12">
|
||||
<div class="form-group">
|
||||
<label for="server">{{ translate('serverWizard', 'zipPath', data['lang']) }} <small>{{
|
||||
translate('serverWizard', 'absoluteZipPath', data['lang']) }}</small></label>
|
||||
<input type="text" class="form-control" id="server_path" name="server_path"
|
||||
placeholder="/var/opt/server.zip" required>
|
||||
</div>
|
||||
<input type="text" class="form-control" id="server_path" name="server_path" placeholder="/var/opt/server.zip" required>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-12">
|
||||
<div class="form-group">
|
||||
<label for="server">{{ translate('serverWizard', 'selectRoot', data['lang']) }} <small>{{
|
||||
translate('serverWizard', 'explainRoot', data['lang']) }}</small></label>
|
||||
@ -228,44 +208,23 @@
|
||||
<button class="btn btn-primary mr-2" id="root_files_button" type="button">{{
|
||||
translate('serverWizard', 'clickRoot', data['lang']) }}</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="col-sm-12">
|
||||
<div class="form-group">
|
||||
<label for="server_jar">{{ translate('serverWizard', 'serverJar', data['lang']) }}</label>
|
||||
<input type="text" class="form-control" id="server_jar" name="server_jar" value=""
|
||||
placeholder="bedrock_server" required>
|
||||
<input type="text" class="form-control" id="server_jar" name="server_jar" value="" placeholder="bedrock_server" required>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="col-sm-12">
|
||||
<h4 class="card-title">{{ translate('serverWizard', 'quickSettings', data['lang']) }} <small
|
||||
style="text-transform: none;"> - {{ translate('serverWizard', 'quickSettingsDescription',
|
||||
data['lang']) }}</small></h4>
|
||||
<h4 class="card-title">{{ translate('serverWizard', 'quickSettings', data['lang']) }} <small style="text-transform: none;"> - {{ translate('serverWizard', 'quickSettingsDescription', data['lang']) }}</small>
|
||||
</h4>
|
||||
<hr>
|
||||
<div class="row">
|
||||
|
||||
<div class="col-sm-12">
|
||||
<div class="form-group">
|
||||
<label for="port3">{{ translate('serverWizard', 'serverPort', data['lang']) }}
|
||||
<small></small></label>
|
||||
<input type="number" class="form-control" id="port3" name="port" value="19132" step="1" min="1"
|
||||
max="65535" required>
|
||||
<input type="number" class="form-control" id="port3" name="port" value="19132" step="1" min="1" max="65535" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-12">
|
||||
<div class="form-group">
|
||||
<div id="accordion-3">
|
||||
<div class="card">
|
||||
<div class="card-header p-2" id="Role-3">
|
||||
<p class="mb-0 p-0" data-toggle="collapse" data-target="#collapseRole-3" aria-expanded="true"
|
||||
aria-controls="collapseRole-3">
|
||||
<p class="mb-0 p-0" data-toggle="collapse" data-target="#collapseRole-3" aria-expanded="true" aria-controls="collapseRole-3">
|
||||
<i class="fas fa-chevron-down"></i> {{ translate('serverWizard', 'addRole', data['lang'])
|
||||
}} <small style="text-transform: none;"> - {{ translate('serverWizard', 'autoCreate',
|
||||
data['lang']) }}</small>
|
||||
@ -275,8 +234,7 @@
|
||||
<div class="card-body scroll">
|
||||
<div class="form-group">
|
||||
{% for r in data['roles'] %}
|
||||
<span class="d-block menu-option"><label><input name="{{ r['role_id'] }}"
|
||||
type="checkbox">
|
||||
<span class="d-block menu-option"><label><input name="{{ r['role_id'] }}" type="checkbox">
|
||||
{{ r['role_name'].capitalize() }}</label></span>
|
||||
{% end %}
|
||||
</div>
|
||||
@ -285,14 +243,12 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-12" style="visibility: hidden;">
|
||||
<div style="visibility: hidden;">
|
||||
<div class="form-group">
|
||||
<input type="text" class="form-control" id="zip_root_path" name="zip_root_path">
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal fade" id="dir_select" tabindex="-1" role="dialog" aria-labelledby="dir_select"
|
||||
aria-hidden="true">
|
||||
<div class="modal fade" id="dir_select" tabindex="-1" role="dialog" aria-labelledby="dir_select" aria-hidden="true">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
@ -303,8 +259,7 @@
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="tree-ctx-item" id="main-tree-div" data-path=""
|
||||
style="overflow: scroll; max-height:75%;">
|
||||
<div class="tree-ctx-item" id="main-tree-div" data-path="" style="overflow: scroll; max-height:75%;">
|
||||
<input type="radio" id="main-tree-input" name="root_path" value="" checked>
|
||||
<span id="main-tree" class="files-tree-title tree-caret-down root-dir" data-path="">
|
||||
<i class="far fa-folder"></i>
|
||||
@ -323,20 +278,16 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button id="zip_submit" type="submit" title="You must select server root dir first" disabled
|
||||
class="btn btn-primary mr-2">{{ translate('serverWizard', 'importServerButton', data['lang'])
|
||||
<button id="zip_submit" type="submit" title="You must select server root dir first" disabled class="btn btn-primary mr-2">{{ translate('serverWizard', 'importServerButton', data['lang'])
|
||||
}}</button>
|
||||
<button type="button" class="btn btn-danger mr-2 tree-reset">{{ translate('serverWizard', 'resetForm',
|
||||
data['lang'])
|
||||
}}</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-6 grid-margin stretch-card">
|
||||
</div>
|
||||
<div class="col-md-6 grid-margin stretch-card">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
|
||||
@ -348,30 +299,25 @@
|
||||
{% raw xsrf_form_html() %}
|
||||
<input type="hidden" value="import_zip" name="create_type">
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<div class="col-sm-12">
|
||||
<div class="form-group">
|
||||
<label for="server_name">{{ translate('serverWizard', 'serverName', data['lang']) }}</label>
|
||||
<input type="text" class="form-control" id="server_name" name="server_name" value=""
|
||||
placeholder="{{ translate('serverWizard', 'myNewServer', data['lang']) }}" required>
|
||||
</div>
|
||||
<input type="text" class="form-control" id="server_name" name="server_name" value="" placeholder="{{ translate('serverWizard', 'myNewServer', data['lang']) }}" required>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-12">
|
||||
<div class="form-group">
|
||||
<label for="server">{{ translate('serverWizard', 'serverUpload', data['lang']) }}</label><br>
|
||||
<span id="upload_input">
|
||||
<input type="file" multiple="false" class="form-control" id="file" name="file" required
|
||||
style="width: 70%;">
|
||||
<button type="button" class="btn btn-info" onclick="sendFile()">{{ translate('serverWizard',
|
||||
<label for="server">Server Upload </label>
|
||||
<div id="upload_input" class="input-group">
|
||||
<div class="custom-file">
|
||||
<input type="file" multiple="false" class="custom-file-input" id="file" name="file" required>
|
||||
<label id="fileLabel" class="custom-file-label" for="file">{{ translate('serverWizard', 'labelZipFile', data['lang']) }}</label>
|
||||
</div>
|
||||
<div class="input-group-append">
|
||||
<button type="button" class="btn btn-info upload-button" id="upload-button" onclick="sendFile()" disabled>{{ translate('serverWizard',
|
||||
'uploadButton', data['lang']) }}</button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="lower_half" style="visibility: hidden;">
|
||||
<div class="col-sm-12">
|
||||
<div class="form-group">
|
||||
<label for="server">{{ translate('serverWizard', 'selectRoot', data['lang']) }} <small>{{
|
||||
translate('serverWizard', 'explainRoot', data['lang']) }}</small></label>
|
||||
@ -379,40 +325,28 @@
|
||||
<button class="btn btn-primary mr-2" id="root_upload_button" type="button">{{
|
||||
translate('serverWizard', 'clickRoot', data['lang']) }}</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="col-sm-12">
|
||||
<div class="form-group">
|
||||
<label for="server_jar">{{ translate('serverWizard', 'serverJar', data['lang']) }}</label>
|
||||
<input type="text" class="form-control" id="server_jar" name="server_jar" value=""
|
||||
placeholder="paper.jar" required>
|
||||
</div>
|
||||
<input type="text" class="form-control" id="server_jar" name="server_jar" value="" placeholder="paper.jar" required>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-12">
|
||||
<h4 class="card-title">{{ translate('serverWizard', 'quickSettings', data['lang']) }} <small
|
||||
style="text-transform: none;"> - {{ translate('serverWizard', 'quickSettingsDescription',
|
||||
<h4 class="card-title">{{ translate('serverWizard', 'quickSettings', data['lang']) }} <small style="text-transform: none;"> - {{ translate('serverWizard', 'quickSettingsDescription',
|
||||
data['lang']) }}</small></h4>
|
||||
<hr>
|
||||
<div class="row">
|
||||
|
||||
<div class="col-sm-12">
|
||||
<div class="form-group">
|
||||
<label for="port3">{{ translate('serverWizard', 'serverPort', data['lang']) }} <small> - {{
|
||||
translate('serverWizard', 'defaultPort', data['lang']) }}</small></label>
|
||||
<input type="number" class="form-control" id="port4" name="port" value="19132" step="1" min="1"
|
||||
max="65535" required>
|
||||
</div>
|
||||
<input type="number" class="form-control" id="port4" name="port" value="19132" step="1" min="1" max="65535" required>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-12">
|
||||
<div class="form-group">
|
||||
<div id="accordion-3">
|
||||
<div class="card">
|
||||
<div class="card-header p-2" id="Role-3">
|
||||
<p class="mb-0 p-0" data-toggle="collapse" data-target="#collapseRole-3"
|
||||
aria-expanded="true" aria-controls="collapseRole-3">
|
||||
<p class="mb-0 p-0" data-toggle="collapse" data-target="#collapseRole-3" aria-expanded="true" aria-controls="collapseRole-3">
|
||||
<i class="fas fa-chevron-down"></i> {{ translate('serverWizard', 'addRole',
|
||||
data['lang'])
|
||||
}} <small style="text-transform: none;"> - {{ translate('serverWizard', 'autoCreate',
|
||||
@ -423,8 +357,7 @@
|
||||
<div class="card-body scroll">
|
||||
<div class="form-group">
|
||||
{% for r in data['roles'] %}
|
||||
<span class="d-block menu-option"><label><input name="{{ r['role_id'] }}"
|
||||
type="checkbox">
|
||||
<span class="d-block menu-option"><label><input name="{{ r['role_id'] }}" type="checkbox">
|
||||
{{ r['role_name'].capitalize() }}</label></span>
|
||||
{% end %}
|
||||
</div>
|
||||
@ -433,14 +366,12 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-12" style="visibility: hidden;">
|
||||
<div style="visibility: hidden;">
|
||||
<div class="form-group">
|
||||
<input type="text" class="form-control" id="zip_root_path" name="zip_root_path">
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal fade" id="dir_upload_select" tabindex="-1" role="dialog"
|
||||
aria-labelledby="dir_select" aria-hidden="true">
|
||||
<div class="modal fade" id="dir_upload_select" tabindex="-1" role="dialog" aria-labelledby="dir_select" aria-hidden="true">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
@ -451,8 +382,7 @@
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="tree-ctx-item" id="main-tree-div-upload" data-path=""
|
||||
style="overflow: scroll; max-height:75%;">
|
||||
<div class="tree-ctx-item" id="main-tree-div-upload" data-path="" style="overflow: scroll; max-height:75%;">
|
||||
<input type="radio" id="main-tree-input-upload" name="root_path" value="" checked>
|
||||
<span id="main-tree" class="files-tree-title tree-caret-down root-dir" data-path="">
|
||||
<i class="far fa-folder"></i>
|
||||
@ -471,18 +401,13 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button id="upload_submit" type="submit" title="You must select server root dir first" disabled
|
||||
class="btn btn-primary mr-2">{{ translate('serverWizard', 'importServerButton', data['lang'])
|
||||
<button id="upload_submit" type="submit" title="You must select server root dir first" disabled class="btn btn-primary mr-2">{{ translate('serverWizard', 'importServerButton', data['lang'])
|
||||
}}</button>
|
||||
<button type="button" class="btn btn-danger mr-2 tree-reset">{{ translate('serverWizard', 'resetForm',
|
||||
data['lang'])
|
||||
}}</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -494,6 +419,15 @@
|
||||
font-size: 10px;
|
||||
vertical-align: top;
|
||||
}
|
||||
div>.input-group>.custom-file-input {
|
||||
position: relative !important;
|
||||
-webkit-box-flex: 1 !important;
|
||||
-ms-flex: 1 1 auto !important;
|
||||
flex: 1 1 auto !important;
|
||||
width: 1% !important;
|
||||
margin-bottom: 0 !important;
|
||||
border: 1px solid var(--outline);
|
||||
}
|
||||
|
||||
.scroll {
|
||||
max-height: 12em;
|
||||
@ -583,7 +517,7 @@
|
||||
var file;
|
||||
function sendFile() {
|
||||
file = $("#file")[0].files[0]
|
||||
document.getElementById("upload_input").innerHTML = '<div class="progress"><div id="upload-progress-bar" class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100" style="width: 100%"> <i class="fa-solid fa-spinner"></i></div></div>'
|
||||
document.getElementById("upload_input").innerHTML = '<div class="progress" style="width: 100%;"><div class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100" style="width: 100%"> <i class="fa-solid fa-spinner"></i></div></div>'
|
||||
let xmlHttpRequest = new XMLHttpRequest();
|
||||
let token = getCookie("_xsrf")
|
||||
let fileName = encodeURIComponent(file.name)
|
||||
@ -611,7 +545,7 @@
|
||||
xmlHttpRequest.addEventListener('load', (event) => {
|
||||
if (event.target.responseText == 'success') {
|
||||
console.log('Upload for file', file.name, 'was successful!')
|
||||
document.getElementById("upload_input").innerHTML = '<div class="card-header header-sm d-flex justify-content-between align-items-center"><span id="file-uploaded" style="color: gray;">' + fileName + '</span> 🔒</div>';
|
||||
document.getElementById("upload_input").innerHTML = '<div class="card-header header-sm d-flex justify-content-between align-items-center" style="width: 100%;"><span id="file-uploaded" style="color: gray;">' + fileName + '</span> 🔒</div>';
|
||||
document.getElementById("lower_half").style.visibility = "visible";
|
||||
}
|
||||
else {
|
||||
@ -864,5 +798,15 @@
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
$('#file').change(function () {
|
||||
console.log("File changed");
|
||||
if ($('#file').val()) {
|
||||
$('#upload-button').prop("disabled", false);
|
||||
document.getElementById("fileLabel").innerHTML = $('#file').val().split('\\').pop().split('/').pop();
|
||||
console.log("File changed good");
|
||||
}
|
||||
});
|
||||
|
||||
</script>
|
||||
{% end %}
|
@ -39,7 +39,8 @@
|
||||
<div class="form-group">
|
||||
<label for="server_jar">{{ translate('serverWizard', 'serverType', data['lang'])
|
||||
}}</label></br>
|
||||
<select style="width: 80%" required class="selectpicker form-control form-control-lg select-css"
|
||||
<div class="input-group">
|
||||
<select data-container="body" required class="selectpicker form-control form-control-lg select-css"
|
||||
id="steam_server" data-live-search="true" name="steam_server">
|
||||
<option value="None">None</option>
|
||||
{% for s in data['servers'] %}
|
||||
@ -50,12 +51,15 @@
|
||||
{% end %}
|
||||
{% end %}
|
||||
</select>
|
||||
|
||||
{% if data['super_user'] %}
|
||||
<i onclick="refreshCache()" style="float: left;" id="refresh-cache"
|
||||
class="refresh-class fas fa-sync"></i>
|
||||
<div class="input-group-append">
|
||||
<button class="btn custom-picker" type="button" onclick="refreshCache()"><i id="refresh-cache" class="refresh-class fas fa-sync"></i></button>
|
||||
</div>
|
||||
{% end %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-12">
|
||||
<div class="form-group">
|
||||
<label for="server_name">{{ translate('serverWizard', 'serverName', data['lang']) }}</label>
|
||||
|
@ -31,45 +31,79 @@
|
||||
</ul>
|
||||
<div class="d-none" id="overlay" onclick="hide(event)"></div>
|
||||
<div class="row">
|
||||
{% if data['online'] %}
|
||||
<div class="col-sm-6 grid-margin stretch-card">
|
||||
<div class="card">
|
||||
<div class="card" id="creation_wizard">
|
||||
<div class="card-body">
|
||||
{% if data["server_api"] and data["online"] %}
|
||||
<a href="https://serverjars.com/" target="_blank" alt="serverjars icon"><img src="../../static/assets/images/serverjars/ICON.svg"
|
||||
style="float: right; width: 40px; position: relative;"></a>
|
||||
{% end %}
|
||||
|
||||
<h4>{{ translate('serverWizard', 'newServer', data['lang']) }}</h4>
|
||||
<br />
|
||||
<p class="card-description">
|
||||
|
||||
<form method="post" class="server-wizard" onSubmit="wait_msg()">
|
||||
{% if data["server_api"] and data["online"] %}
|
||||
<fieldset>
|
||||
{% else %}
|
||||
<fieldset disabled="disabled">
|
||||
<style>
|
||||
#creation_wizard {
|
||||
-webkit-filter: grayscale(1);
|
||||
}
|
||||
|
||||
.api-alert {
|
||||
position: absolute;
|
||||
top: -5px;
|
||||
left: 0;
|
||||
font-size: 50px !important;
|
||||
color: #fff;
|
||||
background: rgb(0, 170, 170);
|
||||
opacity: .4;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.api-alert p {
|
||||
margin: 0;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
text-align: center;
|
||||
font-size: 20px;
|
||||
-ms-transform: translate(-50%, -50%);
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
</style>
|
||||
{% end %}
|
||||
{% raw xsrf_form_html() %}
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<div class="form-group">
|
||||
<label for="server_jar">{{ translate('serverWizard', 'serverType', data['lang'])
|
||||
}}</label>
|
||||
{% if data['super_user'] %}
|
||||
<select style="width: 90%;" required class="form-control form-control-lg select-css" id="server_jar"
|
||||
name="server_jar" onchange="serverJarChange(this)">
|
||||
{% else %}
|
||||
<select required class="form-control form-control-lg select-css" id="server_jar" name="server_jar"
|
||||
onchange="serverJarChange(this)">
|
||||
{% end %}
|
||||
<div class="input-group">
|
||||
<select required class="form-control form-control-lg select-css" id="server_jar" name="server_jar" onchange="serverJarChange(this)">
|
||||
<option value="None">{{ translate('serverWizard', 'selectType', data['lang']) }}</option>
|
||||
{% for s in data['server_types'] %}
|
||||
<option value="{{ s }}">{{ s.capitalize() }}</option>
|
||||
{% end %}
|
||||
</select>
|
||||
{% if data['super_user'] %}
|
||||
<i onclick="refreshCache()" id="refresh-cache" class="refresh-class fas fa-sync"></i>
|
||||
<div class="input-group-append">
|
||||
<button class="btn custom-picker" type="button" onclick="refreshCache()"><i id="refresh-cache" class="refresh-class fas fa-sync"></i></button>
|
||||
</div>
|
||||
{% end %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-12">
|
||||
<div class="form-group">
|
||||
<label for="server_type">{{ translate('serverWizard', 'serverSelect', data['lang']) }}</label>
|
||||
<select required class="form-control form-control-lg select-css" id="server_type" name="server_type"
|
||||
onchange="serverTypeChange(this)">
|
||||
<select required class="form-control form-control-lg select-css" id="server_type" name="server_type" onchange="serverTypeChange(this)">
|
||||
<option value="">{{ translate('serverWizard', 'selectServer', data['lang']) }}</option>
|
||||
</select>
|
||||
</div>
|
||||
@ -87,15 +121,13 @@
|
||||
<div class="col-sm-12">
|
||||
<div class="form-group">
|
||||
<label for="server_name">{{ translate('serverWizard', 'serverName', data['lang']) }}</label>
|
||||
<input type="text" class="form-control" id="server_name" name="server_name"
|
||||
placeholder="{{ translate('serverWizard', 'myNewServer', data['lang']) }}" required>
|
||||
<input type="text" class="form-control" id="server_name" name="server_name" placeholder="{{ translate('serverWizard', 'myNewServer', data['lang']) }}" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<br />
|
||||
<h4 class="card-title">{{ translate('serverWizard', 'quickSettings', data['lang']) }} <small
|
||||
style="text-transform: none;"> - {{ translate('serverWizard', 'quickSettingsDescription',
|
||||
<h4 class="card-title">{{ translate('serverWizard', 'quickSettings', data['lang']) }} <small style="text-transform: none;"> - {{ translate('serverWizard', 'quickSettingsDescription',
|
||||
data['lang']) }}</small></h4>
|
||||
<hr>
|
||||
<div class="row">
|
||||
@ -104,8 +136,7 @@
|
||||
<div class="form-group">
|
||||
<label for="min_memory1">{{ translate('serverWizard', 'minMem', data['lang']) }} <small> - {{
|
||||
translate('serverWizard', 'sizeInGB', data['lang']) }}</small></label>
|
||||
<input type="number" class="form-control" id="min_memory1" name="min_memory" value="1" step="0.5"
|
||||
min="0.5" required>
|
||||
<input type="number" class="form-control" id="min_memory1" name="min_memory" value="1" step="0.5" min="0.5" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -113,8 +144,7 @@
|
||||
<div class="form-group">
|
||||
<label for="max_memory1">{{ translate('serverWizard', 'maxMem', data['lang']) }} <small> - {{
|
||||
translate('serverWizard', 'sizeInGB', data['lang']) }}</small></label>
|
||||
<input type="number" class="form-control" id="max_memory1" name="max_memory" value="2" step="0.5"
|
||||
min="0.5" required>
|
||||
<input type="number" class="form-control" id="max_memory1" name="max_memory" value="2" step="0.5" min="0.5" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -122,8 +152,7 @@
|
||||
<div class="form-group">
|
||||
<label for="port1">{{ translate('serverWizard', 'serverPort', data['lang']) }} <small> - {{
|
||||
translate('serverWizard', 'defaultPort', data['lang']) }}</small></label>
|
||||
<input type="number" class="form-control" id="port1" name="port" value="25565" step="1" min="1"
|
||||
max="65535 " required>
|
||||
<input type="number" class="form-control" id="port1" name="port" value="25565" step="1" min="1" max="65535 " required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-12">
|
||||
@ -131,8 +160,7 @@
|
||||
<div id="accordion-1">
|
||||
<div class="card">
|
||||
<div class="card-header p-2" id="Role-1">
|
||||
<p class="mb-0 p-0" data-toggle="collapse" data-target="#collapseRole-1" aria-expanded="true"
|
||||
aria-controls="collapseRole-1">
|
||||
<p class="mb-0 p-0" data-toggle="collapse" data-target="#collapseRole-1" aria-expanded="true" aria-controls="collapseRole-1">
|
||||
<i class="fas fa-chevron-down"></i> {{ translate('serverWizard', 'addRole', data['lang']) }}
|
||||
<small style="text-transform: none;"> - {{ translate('serverWizard', 'autoCreate',
|
||||
data['lang']) }}</small>
|
||||
@ -142,9 +170,7 @@
|
||||
<div class="card-body scroll">
|
||||
<div class="form-group">
|
||||
{% for r in data['roles'] %}
|
||||
<span class="d-block menu-option"><label><input name="{{ r['role_id'] }}"
|
||||
type="checkbox">
|
||||
{{ r['role_name'].capitalize() }}</label></span>
|
||||
<span class="d-block menu-option"><label><input name="{{ r['role_id'] }}" type="checkbox"> {{ r['role_name'].capitalize() }}</label></span>
|
||||
{% end %}
|
||||
</div>
|
||||
</div>
|
||||
@ -159,15 +185,25 @@
|
||||
data['lang']) }}</button>
|
||||
<button type="reset" class="btn btn-danger mr-2">{{ translate('serverWizard', 'resetForm', data['lang'])
|
||||
}}</button>
|
||||
|
||||
</form>
|
||||
</p>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
</fieldset>
|
||||
{% if not data["server_api"] and data["online"] %}
|
||||
<div class="api-alert" style="position: absolute; top: -5px; z-index: 100; opacity: .99;">
|
||||
<p style="color: white !important;"><i class="fas fa-exclamation-triangle" style="color: red;"></i> {{ translate('error', 'serverJars1', data['lang']) }}<a style="color: red;"; href="https://status.craftycontrol.com/status/craftycontrol"
|
||||
target="_blank"> {{ translate('error', 'craftyStatus', data['lang']) }}</a>
|
||||
{{ translate('error', 'serverJars2', data['lang']) }}</p></div>
|
||||
{% end %}
|
||||
{% if not data["online"] %}
|
||||
<div class="api-alert" style="position: absolute; top: -5px; z-index: 100; opacity: .99;">
|
||||
<p style="color: white !important;"><i class="fas fa-exclamation-triangle" style="color: red;"></i> {{ translate('error', 'noInternet', data['lang']) }}</p></div>
|
||||
{% end %}
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-6 grid-margin stretch-card">
|
||||
<!-- Import an Existing Server -->
|
||||
<div class="col-md-6 grid-margin stretch-card">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
|
||||
@ -183,8 +219,7 @@
|
||||
<div class="col-sm-12">
|
||||
<div class="form-group">
|
||||
<label for="server_name">{{ translate('serverWizard', 'serverName', data['lang']) }}</label>
|
||||
<input type="text" class="form-control" id="server_name" name="server_name" value=""
|
||||
placeholder="{{ translate('serverWizard', 'myNewServer', data['lang']) }}" required>
|
||||
<input type="text" class="form-control" id="server_name" name="server_name" value="" placeholder="{{ translate('serverWizard', 'myNewServer', data['lang']) }}" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -192,16 +227,14 @@
|
||||
<div class="form-group">
|
||||
<label for="server">{{ translate('serverWizard', 'serverPath', data['lang']) }} <small>{{
|
||||
translate('serverWizard', 'absoluteServerPath', data['lang']) }}</small></label>
|
||||
<input type="text" class="form-control" id="server_path" name="server_path"
|
||||
placeholder="/var/opt/server" required>
|
||||
<input type="text" class="form-control" id="server_path" name="server_path" placeholder="/var/opt/server" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-12">
|
||||
<div class="form-group">
|
||||
<label for="server_jar">{{ translate('serverWizard', 'serverJar', data['lang']) }}</label>
|
||||
<input type="text" class="form-control" id="server_jar" name="server_jar" value=""
|
||||
placeholder="paper.jar" required>
|
||||
<input type="text" class="form-control" id="server_jar" name="server_jar" value="" placeholder="paper.jar" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -209,8 +242,7 @@
|
||||
|
||||
</div>
|
||||
<br />
|
||||
<h4 class="card-title">{{ translate('serverWizard', 'quickSettings', data['lang']) }} <small
|
||||
style="text-transform: none;"> - {{ translate('serverWizard', 'quickSettingsDescription',
|
||||
<h4 class="card-title">{{ translate('serverWizard', 'quickSettings', data['lang']) }} <small style="text-transform: none;"> - {{ translate('serverWizard', 'quickSettingsDescription',
|
||||
data['lang']) }}</small></h4>
|
||||
<hr>
|
||||
<div class="row">
|
||||
@ -219,8 +251,7 @@
|
||||
<div class="form-group">
|
||||
<label for="min_memory2">{{ translate('serverWizard', 'minMem', data['lang']) }} <small> - {{
|
||||
translate('serverWizard', 'sizeInGB', data['lang']) }}</small></label>
|
||||
<input type="number" class="form-control" id="min_memory2" name="min_memory" value="1" step="0.5"
|
||||
min="0.5" required>
|
||||
<input type="number" class="form-control" id="min_memory2" name="min_memory" value="1" step="0.5" min="0.5" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -228,8 +259,7 @@
|
||||
<div class="form-group">
|
||||
<label for="max_memory2">{{ translate('serverWizard', 'maxMem', data['lang']) }} <small> - {{
|
||||
translate('serverWizard', 'sizeInGB', data['lang']) }}</small></label>
|
||||
<input type="number" class="form-control" id="max_memory2" name="max_memory" value="2" step="0.5"
|
||||
min="0.5" required>
|
||||
<input type="number" class="form-control" id="max_memory2" name="max_memory" value="2" step="0.5" min="0.5" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -237,8 +267,7 @@
|
||||
<div class="form-group">
|
||||
<label for="port2">{{ translate('serverWizard', 'serverPort', data['lang']) }} <small> - {{
|
||||
translate('serverWizard', 'defaultPort', data['lang']) }}</small></label>
|
||||
<input type="number" class="form-control" id="port2" name="port" value="25565" step="1" min="1"
|
||||
max="65535" required>
|
||||
<input type="number" class="form-control" id="port2" name="port" value="25565" step="1" min="1" max="65535" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-12">
|
||||
@ -246,8 +275,7 @@
|
||||
<div id="accordion-2">
|
||||
<div class="card">
|
||||
<div class="card-header p-2" id="Role-2">
|
||||
<p class="mb-0 p-0" data-toggle="collapse" data-target="#collapseRole-2" aria-expanded="true"
|
||||
aria-controls="collapseRole-2">
|
||||
<p class="mb-0 p-0" data-toggle="collapse" data-target="#collapseRole-2" aria-expanded="true" aria-controls="collapseRole-2">
|
||||
<i class="fas fa-chevron-down"></i> {{ translate('serverWizard', 'addRole', data['lang']) }}
|
||||
<small style="text-transform: none;"> - {{ translate('serverWizard', 'autoCreate',
|
||||
data['lang']) }}</small>
|
||||
@ -257,8 +285,7 @@
|
||||
<div class="card-body scroll">
|
||||
<div class="form-group">
|
||||
{% for r in data['roles'] %}
|
||||
<span class="d-block menu-option"><label><input name="{{ r['role_id'] }}"
|
||||
type="checkbox">
|
||||
<span class="d-block menu-option"><label><input name="{{ r['role_id'] }}" type="checkbox">
|
||||
{{ r['role_name'].capitalize() }}</label></span>
|
||||
{% end %}
|
||||
</div>
|
||||
@ -279,9 +306,9 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-6 grid-margin stretch-card">
|
||||
|
||||
<!-- Import from a Zip File -->
|
||||
<div class="col-md-6 grid-margin stretch-card">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
|
||||
@ -298,8 +325,7 @@
|
||||
<div class="col-sm-12">
|
||||
<div class="form-group">
|
||||
<label for="server_name">{{ translate('serverWizard', 'serverName', data['lang']) }}</label>
|
||||
<input type="text" class="form-control" id="server_name" name="server_name" value=""
|
||||
placeholder="{{ translate('serverWizard', 'myNewServer', data['lang']) }}" required>
|
||||
<input type="text" class="form-control" id="server_name" name="server_name" value="" placeholder="{{ translate('serverWizard', 'myNewServer', data['lang']) }}" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -307,8 +333,7 @@
|
||||
<div class="form-group">
|
||||
<label for="server">{{ translate('serverWizard', 'zipPath', data['lang']) }} <small>{{
|
||||
translate('serverWizard', 'absoluteZipPath', data['lang']) }}</small></label>
|
||||
<input type="text" class="form-control" id="server_path" name="server_path"
|
||||
placeholder="/var/opt/server.zip" required>
|
||||
<input type="text" class="form-control" id="server_path" name="server_path" placeholder="/var/opt/server.zip" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -326,8 +351,7 @@
|
||||
<div class="col-sm-12">
|
||||
<div class="form-group">
|
||||
<label for="server_jar">{{ translate('serverWizard', 'serverJar', data['lang']) }}</label>
|
||||
<input type="text" class="form-control" id="server_jar" name="server_jar" value=""
|
||||
placeholder="paper.jar" required>
|
||||
<input type="text" class="form-control" id="server_jar" name="server_jar" value="" placeholder="paper.jar" required>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -336,36 +360,31 @@
|
||||
|
||||
|
||||
<div class="col-sm-12">
|
||||
<h4 class="card-title">{{ translate('serverWizard', 'quickSettings', data['lang']) }} <small
|
||||
style="text-transform: none;"> - {{ translate('serverWizard', 'quickSettingsDescription',
|
||||
<h4 class="card-title">{{ translate('serverWizard', 'quickSettings', data['lang']) }} <small style="text-transform: none;"> - {{ translate('serverWizard', 'quickSettingsDescription',
|
||||
data['lang']) }}</small></h4>
|
||||
<hr>
|
||||
<div class="row">
|
||||
|
||||
<div class="col-sm-12">
|
||||
<div class="col-sm-4">
|
||||
<div class="form-group">
|
||||
<label for="min_memory3">{{ translate('serverWizard', 'minMem', data['lang']) }} <small> - {{
|
||||
translate('serverWizard', 'sizeInGB', data['lang']) }}</small></label>
|
||||
<input type="number" class="form-control" id="min_memory3" name="min_memory" value="1" step="0.5"
|
||||
min="0.5" required>
|
||||
<input type="number" class="form-control" id="min_memory3" name="min_memory" value="1" step="0.5" min="0.5" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-12">
|
||||
<div class="col-sm-4">
|
||||
<div class="form-group">
|
||||
<label for="max_memory3">{{ translate('serverWizard', 'maxMem', data['lang']) }} <small> - {{
|
||||
translate('serverWizard', 'sizeInGB', data['lang']) }}</small></label>
|
||||
<input type="number" class="form-control" id="max_memory3" name="max_memory" value="2" step="0.5"
|
||||
min="0.5" required>
|
||||
<input type="number" class="form-control" id="max_memory3" name="max_memory" value="2" step="0.5" min="0.5" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-12">
|
||||
<div class="col-sm-4">
|
||||
<div class="form-group">
|
||||
<label for="port3">{{ translate('serverWizard', 'serverPort', data['lang']) }} <small> - {{
|
||||
translate('serverWizard', 'defaultPort', data['lang']) }}</small></label>
|
||||
<input type="number" class="form-control" id="port3" name="port" value="25565" step="1" min="1"
|
||||
max="65535" required>
|
||||
<input type="number" class="form-control" id="port3" name="port" value="25565" step="1" min="1" max="65535" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -374,8 +393,7 @@
|
||||
<div id="accordion-3">
|
||||
<div class="card">
|
||||
<div class="card-header p-2" id="Role-3">
|
||||
<p class="mb-0 p-0" data-toggle="collapse" data-target="#collapseRole-3" aria-expanded="true"
|
||||
aria-controls="collapseRole-3">
|
||||
<p class="mb-0 p-0" data-toggle="collapse" data-target="#collapseRole-3" aria-expanded="true" aria-controls="collapseRole-3">
|
||||
<i class="fas fa-chevron-down"></i> {{ translate('serverWizard', 'addRole', data['lang'])
|
||||
}} <small style="text-transform: none;"> - {{ translate('serverWizard', 'autoCreate',
|
||||
data['lang']) }}</small>
|
||||
@ -385,8 +403,7 @@
|
||||
<div class="card-body scroll">
|
||||
<div class="form-group">
|
||||
{% for r in data['roles'] %}
|
||||
<span class="d-block menu-option"><label><input name="{{ r['role_id'] }}"
|
||||
type="checkbox">
|
||||
<span class="d-block menu-option"><label><input name="{{ r['role_id'] }}" type="checkbox">
|
||||
{{ r['role_name'].capitalize() }}</label></span>
|
||||
{% end %}
|
||||
</div>
|
||||
@ -396,13 +413,12 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-12" style="visibility: hidden;">
|
||||
<div class="col-sm-12" style="visibility: hidden;" hidden>
|
||||
<div class="form-group">
|
||||
<input type="text" class="form-control" id="zip_root_path" name="zip_root_path">
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal fade" id="dir_select" tabindex="-1" role="dialog" aria-labelledby="dir_select"
|
||||
aria-hidden="true">
|
||||
<div class="modal fade" id="dir_select" tabindex="-1" role="dialog" aria-labelledby="dir_select" aria-hidden="true">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
@ -413,8 +429,7 @@
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="tree-ctx-item" id="main-tree-div" data-path=""
|
||||
style="overflow: scroll; max-height:75%;">
|
||||
<div class="tree-ctx-item" id="main-tree-div" data-path="" style="overflow: scroll; max-height:75%;">
|
||||
<input type="radio" id="main-tree-input" name="root_path" value="" checked>
|
||||
<span id="main-tree" class="files-tree-title tree-caret-down root-dir" data-path="">
|
||||
<i class="far fa-folder"></i>
|
||||
@ -434,8 +449,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button id="zip_submit" type="submit" title="You must select server root dir first" disabled
|
||||
class="btn btn-primary mr-2">{{ translate('serverWizard', 'importServerButton', data['lang'])
|
||||
<button id="zip_submit" type="submit" title="You must select server root dir first" disabled class="btn btn-primary mr-2">{{ translate('serverWizard', 'importServerButton', data['lang'])
|
||||
}}</button>
|
||||
<button type="button" class="btn btn-danger mr-2 tree-reset">{{ translate('serverWizard', 'resetForm',
|
||||
data['lang'])
|
||||
@ -446,7 +460,8 @@
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-6 grid-margin stretch-card">
|
||||
<!-- Upload Zip File For Server Import -->
|
||||
<div class="col-md-6 grid-margin stretch-card">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
|
||||
@ -458,30 +473,25 @@
|
||||
{% raw xsrf_form_html() %}
|
||||
<input type="hidden" value="import_zip" name="create_type">
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<div class="col-sm-12">
|
||||
<div class="form-group">
|
||||
<label for="server_name">{{ translate('serverWizard', 'serverName', data['lang']) }}</label>
|
||||
<input type="text" class="form-control" id="server_name" name="server_name" value=""
|
||||
placeholder="{{ translate('serverWizard', 'myNewServer', data['lang']) }}" required>
|
||||
<input type="text" class="form-control" id="server_name" name="server_name" value="" placeholder="{{ translate('serverWizard', 'myNewServer', data['lang']) }}" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="server">{{ translate('serverWizard', 'serverUpload', data['lang']) }}</label>
|
||||
<div id="upload_input" class="input-group">
|
||||
<div class="custom-file">
|
||||
<input type="file" multiple="false" class="custom-file-input" id="file" name="file" required>
|
||||
<label id="fileLabel" class="custom-file-label" for="file">{{ translate('serverWizard', 'labelZipFile', data['lang']) }}</label>
|
||||
</div>
|
||||
<div class="input-group-append">
|
||||
<button type="button" class="btn btn-info upload-button" id="upload-button" onclick="sendFile()" disabled>{{ translate('serverWizard',
|
||||
'uploadButton', data['lang']) }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-12">
|
||||
<div class="form-group">
|
||||
<label for="server">{{ translate('serverWizard', 'serverUpload', data['lang']) }}</label><br>
|
||||
<span id="upload_input">
|
||||
<input type="file" multiple="false" class="form-control" id="file" name="file" required
|
||||
style="width: 70%;">
|
||||
<button type="button" class="btn btn-info" onclick="sendFile()">{{ translate('serverWizard',
|
||||
'uploadButton', data['lang']) }}</button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="lower_half" style="visibility: hidden;">
|
||||
<div class="col-sm-12">
|
||||
<div id="lower_half" style="visibility: hidden;" hidden>
|
||||
<div class="form-group">
|
||||
<label for="server">{{ translate('serverWizard', 'selectRoot', data['lang']) }} <small>{{
|
||||
translate('serverWizard', 'explainRoot', data['lang']) }}</small></label>
|
||||
@ -489,58 +499,39 @@
|
||||
<button class="btn btn-primary mr-2" id="root_upload_button" type="button">{{
|
||||
translate('serverWizard', 'clickRoot', data['lang']) }}</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="col-sm-12">
|
||||
<div class="form-group">
|
||||
<label for="server_jar">{{ translate('serverWizard', 'serverJar', data['lang']) }}</label>
|
||||
<input type="text" class="form-control" id="server_jar" name="server_jar" value=""
|
||||
placeholder="paper.jar" required>
|
||||
</div>
|
||||
<input type="text" class="form-control" id="server_jar" name="server_jar" value="" placeholder="paper.jar" required>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-12">
|
||||
<h4 class="card-title">{{ translate('serverWizard', 'quickSettings', data['lang']) }} <small
|
||||
style="text-transform: none;"> - {{ translate('serverWizard', 'quickSettingsDescription',
|
||||
<h4 class="card-title">{{ translate('serverWizard', 'quickSettings', data['lang']) }} <small style="text-transform: none;"> - {{ translate('serverWizard', 'quickSettingsDescription',
|
||||
data['lang']) }}</small></h4>
|
||||
<hr>
|
||||
<div class="row">
|
||||
|
||||
<div class="col-sm-12">
|
||||
<div class="form-group">
|
||||
<label for="min_memory3">{{ translate('serverWizard', 'minMem', data['lang']) }} <small> - {{
|
||||
translate('serverWizard', 'sizeInGB', data['lang']) }}</small></label>
|
||||
<input type="number" class="form-control" id="min_memory3" name="min_memory" value="1"
|
||||
step="0.5" min="0.5" required>
|
||||
</div>
|
||||
<input type="number" class="form-control" id="min_memory3" name="min_memory" value="1" step="0.5" min="0.5" required>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-12">
|
||||
<div class="form-group">
|
||||
<label for="max_memory3">{{ translate('serverWizard', 'maxMem', data['lang']) }} <small> - {{
|
||||
translate('serverWizard', 'sizeInGB', data['lang']) }}</small></label>
|
||||
<input type="number" class="form-control" id="max_memory3" name="max_memory" value="2"
|
||||
step="0.5" min="0.5" required>
|
||||
</div>
|
||||
<input type="number" class="form-control" id="max_memory3" name="max_memory" value="2" step="0.5" min="0.5" required>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-12">
|
||||
<div class="form-group">
|
||||
<label for="port3">{{ translate('serverWizard', 'serverPort', data['lang']) }} <small> - {{
|
||||
translate('serverWizard', 'defaultPort', data['lang']) }}</small></label>
|
||||
<input type="number" class="form-control" id="port3" name="port" value="25565" step="1" min="1"
|
||||
max="65535" required>
|
||||
</div>
|
||||
<input type="number" class="form-control" id="port3" name="port" value="25565" step="1" min="1" max="65535" required>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-12">
|
||||
<div class="form-group">
|
||||
<div id="accordion-3">
|
||||
<div class="card">
|
||||
<div class="card-header p-2" id="Role-3">
|
||||
<p class="mb-0 p-0" data-toggle="collapse" data-target="#collapseRole-3"
|
||||
aria-expanded="true" aria-controls="collapseRole-3">
|
||||
<p class="mb-0 p-0" data-toggle="collapse" data-target="#collapseRole-3" aria-expanded="true" aria-controls="collapseRole-3">
|
||||
<i class="fas fa-chevron-down"></i> {{ translate('serverWizard', 'addRole',
|
||||
data['lang'])
|
||||
}} <small style="text-transform: none;"> - {{ translate('serverWizard', 'autoCreate',
|
||||
@ -551,8 +542,7 @@
|
||||
<div class="card-body scroll">
|
||||
<div class="form-group">
|
||||
{% for r in data['roles'] %}
|
||||
<span class="d-block menu-option"><label><input name="{{ r['role_id'] }}"
|
||||
type="checkbox">
|
||||
<span class="d-block menu-option"><label><input name="{{ r['role_id'] }}" type="checkbox">
|
||||
{{ r['role_name'].capitalize() }}</label></span>
|
||||
{% end %}
|
||||
</div>
|
||||
@ -561,14 +551,12 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-12" style="visibility: hidden;">
|
||||
<div style="visibility: hidden;">
|
||||
<div class="form-group">
|
||||
<input type="text" class="form-control" id="zip_root_path" name="zip_root_path">
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal fade" id="dir_upload_select" tabindex="-1" role="dialog"
|
||||
aria-labelledby="dir_select" aria-hidden="true">
|
||||
<div class="modal fade" id="dir_upload_select" tabindex="-1" role="dialog" aria-labelledby="dir_select" aria-hidden="true">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
@ -579,11 +567,9 @@
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="tree-ctx-item" id="main-tree-div-upload" data-path=""
|
||||
style="overflow: scroll; max-height:75%;">
|
||||
<div class="tree-ctx-item" id="main-tree-div-upload" data-path="" style="overflow: scroll; max-height:75%;">
|
||||
<input type="radio" id="main-tree-input-upload" name="root_path" value="" checked>
|
||||
<span id="main-tree-upload" class="files-tree-title tree-caret-down root-dir"
|
||||
data-path="">
|
||||
<span id="main-tree-upload" class="files-tree-title tree-caret-down root-dir" data-path="">
|
||||
<i class="far fa-folder"></i>
|
||||
<i class="far fa-folder-open"></i>
|
||||
{{ translate('serverFiles', 'files', data['lang']) }}
|
||||
@ -601,22 +587,24 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button id="upload_submit" type="submit" title="You must select server root dir first" disabled
|
||||
class="btn btn-primary mr-2">{{ translate('serverWizard', 'importServerButton', data['lang'])
|
||||
<button id="upload_submit" type="submit" title="You must select server root dir first" disabled class="btn btn-primary mr-2">{{ translate('serverWizard', 'importServerButton', data['lang'])
|
||||
}}</button>
|
||||
<button type="button" class="btn btn-danger mr-2 tree-reset">{{ translate('serverWizard', 'resetForm',
|
||||
data['lang'])
|
||||
}}</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<style>
|
||||
button>i.refresh-class {
|
||||
margin: 0px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style>
|
||||
.steam::after {
|
||||
content: 'BETA';
|
||||
@ -792,6 +780,7 @@
|
||||
{% end %}
|
||||
|
||||
{% block js%}
|
||||
|
||||
<script>
|
||||
document.getElementById("root_files_button").addEventListener("click", function () {
|
||||
if (document.forms["zip"]["server_path"].value != "") {
|
||||
@ -816,7 +805,6 @@
|
||||
bootbox.alert("You must input a path before selecting this button");
|
||||
}
|
||||
</script>
|
||||
|
||||
{% end %}
|
||||
|
||||
{% block js %}
|
||||
@ -825,7 +813,7 @@
|
||||
var file;
|
||||
function sendFile() {
|
||||
file = $("#file")[0].files[0]
|
||||
document.getElementById("upload_input").innerHTML = '<div class="progress"><div id="upload-progress-bar" class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100" style="width: 100%"> <i class="fa-solid fa-spinner"></i></div></div>'
|
||||
document.getElementById("upload_input").innerHTML = '<div class="progress" style="width: 100%;"><div class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100" style="width: 100%"> <i class="fa-solid fa-spinner"></i></div></div>'
|
||||
let xmlHttpRequest = new XMLHttpRequest();
|
||||
let token = getCookie("_xsrf")
|
||||
let fileName = file.name
|
||||
@ -853,8 +841,9 @@
|
||||
xmlHttpRequest.addEventListener('load', (event) => {
|
||||
if (event.target.responseText == 'success') {
|
||||
console.log('Upload for file', file.name, 'was successful!')
|
||||
document.getElementById("upload_input").innerHTML = '<div class="card-header header-sm d-flex justify-content-between align-items-center"><span id="file-uploaded" style="color: gray;">' + fileName + '</span> 🔒</div>';
|
||||
document.getElementById("upload_input").innerHTML = '<div class="card-header header-sm d-flex justify-content-between align-items-center" style="width: 100%;"><span id="file-uploaded" style="color: gray;">' + fileName + '</span> 🔒</div>';
|
||||
document.getElementById("lower_half").style.visibility = "visible";
|
||||
document.getElementById("lower_half").hidden = false;
|
||||
}
|
||||
else {
|
||||
let response_text = JSON.parse(event.target.responseText);
|
||||
@ -972,12 +961,13 @@
|
||||
function wait_msg(importing) {
|
||||
bootbox.alert({
|
||||
title: importing ? '{% raw translate("serverWizard", "importing", data["lang"]) %}' : '{% raw translate("serverWizard", "downloading", data["lang"]) %}',
|
||||
message: '<i class="fas fa-cloud-download"></i> {% raw translate("serverWizard", "bePatient", data["lang"]) %}',
|
||||
message: importing ? '<i class="fas fa-cloud-download"></i> {% raw translate("serverWizard", "bePatient", data["lang"]) %}': '<i class="fas fa-cloud-download"></i> {% raw translate("serverWizard", "bePatient", data["lang"]) %}<br><br><a href="https://serverjars.com" target="_blank" style="text-align: center;"><img src="../../static/assets/images/serverjars/FULL-WHITE.svg" alt="Powered by serverjars.com" width="40%"></a>',
|
||||
});
|
||||
}
|
||||
|
||||
function show_file_tree() {
|
||||
if (upload) {
|
||||
console.log("upload true")
|
||||
$("#dir_upload_select").modal();
|
||||
} else {
|
||||
$("#dir_select").modal();
|
||||
@ -1133,6 +1123,15 @@
|
||||
});
|
||||
}
|
||||
|
||||
$('#file').change(function () {
|
||||
console.log("File changed");
|
||||
if ($('#file').val()) {
|
||||
$('#upload-button').prop("disabled", false);
|
||||
document.getElementById("fileLabel").innerHTML = $('#file').val().split('\\').pop().split('/').pop();
|
||||
console.log("File changed good");
|
||||
}
|
||||
});
|
||||
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
var text = '{% raw data["js_server_types"] %}';
|
||||
|
@ -186,7 +186,13 @@
|
||||
"terribleFailure": "What a Terrible Failure!",
|
||||
"superError": "You must be a super user to complete this action.",
|
||||
"fileError": "File type must be an image.",
|
||||
"migration": "Crafty's main server storage is being mirgated to a new location. All server starts have been suspended during this time. Please wait while we finish this migration"
|
||||
"migration": "Crafty's main server storage is being mirgated to a new location. All server starts have been suspended during this time. Please wait while we finish this migration",
|
||||
"serverJars1": "Server JARs API unreachable. Please check",
|
||||
"bedrockError": "Bedrock downloads unavailable. Please check",
|
||||
"craftyStatus": "Crafty's status page",
|
||||
"serverJars2": "for the most up to date information.",
|
||||
"cronFormat": "Invalid Cron format detected",
|
||||
"noInternet": "Crafty is having trouble accessing the internet. Server Creation has been disabled. Please check your internet connection and refresh this page."
|
||||
},
|
||||
"footer": {
|
||||
"allRightsReserved": "All rights reserved",
|
||||
@ -197,7 +203,8 @@
|
||||
"forgotPassword": "Forgot Password",
|
||||
"login": "Log In",
|
||||
"password": "Password",
|
||||
"username": "Username"
|
||||
"username": "Username",
|
||||
"viewStatus": "View Public Status Page"
|
||||
},
|
||||
"notify": {
|
||||
"activityLog": "Activity Logs",
|
||||
@ -209,6 +216,10 @@
|
||||
"preparingLogs": " Please wait while we prepare your logs... We`ll send a notification when they`re ready. This may take a while for large deployments.",
|
||||
"supportLogs": "Support Logs"
|
||||
},
|
||||
"offline": {
|
||||
"offline": "Offline",
|
||||
"pleaseConnect": "Please connect to the internet to use Crafty."
|
||||
},
|
||||
"panelConfig": {
|
||||
"adminControls": "Admin Controls",
|
||||
"allowedServers": "Allowed Servers",
|
||||
@ -243,6 +254,7 @@
|
||||
"customLogin": {
|
||||
"customLoginPage": "Customise the Login Page",
|
||||
"loginImage": "Upload a background image for the login screen.",
|
||||
"labelLoginImage": "Choose your Login Background",
|
||||
"backgroundUpload": "Background Upload",
|
||||
"loginBackground": "Login Background Image",
|
||||
"loginOpacity": "Select the Login Window Opacity",
|
||||
@ -539,6 +551,7 @@
|
||||
"importServerButton": "Import Server!",
|
||||
"importZip": "Import from a Zip File",
|
||||
"uploadZip": "Upload Zip File For Server Import",
|
||||
"labelZipFile": "Choose your Zip File",
|
||||
"maxMem": "Maximum Memory",
|
||||
"minMem": "Minimum Memory",
|
||||
"myNewServer": "My New Server",
|
||||
@ -572,7 +585,8 @@
|
||||
"documentation": "Documentation",
|
||||
"navigation": "Navigation",
|
||||
"newServer": "Create New Server",
|
||||
"servers": "Servers"
|
||||
"servers": "Servers",
|
||||
"inApp": "In App Docs"
|
||||
},
|
||||
"userConfig": {
|
||||
"apiKey": "API Keys",
|
||||
|
@ -12,23 +12,23 @@
|
||||
},
|
||||
"apiKeys": {
|
||||
"apiKeys": "Claves API",
|
||||
"auth": "Autorizado? ",
|
||||
"auth": "¿Autorizado? ",
|
||||
"buttons": "Botones",
|
||||
"config": "Configuración",
|
||||
"crafty": "Crafty: ",
|
||||
"created": "Creado",
|
||||
"createNew": "Crear un nuevo API Token",
|
||||
"createNew": "Crear un nuevo Token de API",
|
||||
"deleteKeyConfirmation": "¿Quieres eliminar esta clave de API? Esto no se puede deshacer.",
|
||||
"deleteKeyConfirmationTitle": "¿Eliminar la clave API ${keyId}?",
|
||||
"getToken": "Conseguir un Token",
|
||||
"name": "Nombre",
|
||||
"nameDesc": "Como te gustaria llamar a este API token? ",
|
||||
"nameDesc": "¿Como te gustaría llamar a este Token de API? ",
|
||||
"no": "No",
|
||||
"pageTitle": "Editar las Claves API",
|
||||
"permName": "Nombre del Permiso",
|
||||
"perms": "Permisos",
|
||||
"server": "Servidor: ",
|
||||
"superUser": "Super User",
|
||||
"superUser": "Super Usuario",
|
||||
"yes": "Si"
|
||||
},
|
||||
"base": {
|
||||
@ -39,81 +39,82 @@
|
||||
"hugeDesc": "Un enorme",
|
||||
"pageDescription": "Sin esta gente, Crafty no existiría",
|
||||
"pageTitle": "Créditos",
|
||||
"patreonDesc": "Patreon / Ko-fi supporters!",
|
||||
"patreonDesc": "A nuestros Patreon / Ko-fi Supporters",
|
||||
"patreonOther": "Otro",
|
||||
"patreonSupporter": "A nuestros Patreon / Ko-fi Supporters",
|
||||
"patreonSupporter": "Patreon / Ko-fi supporters!",
|
||||
"patreonUpdate": "Última Actualización:",
|
||||
"retiredStaff": "Staff retirado",
|
||||
"subscriberName": "Nombre",
|
||||
"subscriptionLevel": "Nivel",
|
||||
"supportTeam": "Equipo de soporte y documentación",
|
||||
"thankYou": "GRACIAS",
|
||||
"translationDesc": "a nuestra comunidad, que tradujo!",
|
||||
"translationDesc": "a nuestra comunidad que traduce! [ Activo = 🟢 Inactivo/Retirado = ⚪ ]",
|
||||
"translationName": "Nombre",
|
||||
"translationTitle": "Traducciones de Idiomas",
|
||||
"translationTitle": "Traduccion de Idiomas",
|
||||
"translator": "Traductores"
|
||||
},
|
||||
"dashboard": {
|
||||
"actions": "Acciones",
|
||||
"allServers": "Todos los servidores",
|
||||
"avg": "Avg",
|
||||
"backups": "Backups",
|
||||
"backups": "Respaldos",
|
||||
"bePatientClone": "Espere mientras clonamos el servidor.<br /> Esta pantalla se actualizará en un momento",
|
||||
"bePatientRestart": "Espere mientras reiniciamos el servidor.<br /> Esta pantalla se actualizará en un momento",
|
||||
"bePatientStart": "Espere mientras iniciamos el servidor.<br /> Esta pantalla se actualizará en un momento",
|
||||
"bePatientStop": "Espere mientras detenemos el servidor.<br /> Esta pantalla se actualizará en un momento",
|
||||
"cannotSee": "¿No puedes verlo todo?",
|
||||
"cannotSeeOnMobile": "¿No puedes verlo todo en móvil?",
|
||||
"cannotSeeOnMobile2": "Intenta desplazar la tabla desde los lados..",
|
||||
"cannotSee": "¿No se muestra correctamente?",
|
||||
"cannotSeeOnMobile": "¿No se muestra correctamente en móvil?",
|
||||
"cannotSeeOnMobile2": "Intente girar el dispositivo hacia los lados.",
|
||||
"clone": "Clonar",
|
||||
"cloneConfirm": "¿Está seguro de que desea clonar este servidor? Este proceso puede llevar un tiempo",
|
||||
"cpuCores": "Nucleos de CPU",
|
||||
"cpuCores": "Núcleos de CPU",
|
||||
"cpuCurFreq": "Reloj de CPU Actual",
|
||||
"cpuMaxFreq": "Reloj de CPU Maximo",
|
||||
"cpuMaxFreq": "Reloj de CPU Máximo",
|
||||
"cpuUsage": "Uso de CPU",
|
||||
"crashed": "Crashed",
|
||||
"crashed": "Crasheado",
|
||||
"dashboard": "Panel de control",
|
||||
"delay-explained": "El agente/servicio ha iniciado recientemente y está retrasando el inicio de la instancia del servidor de Minecraft.",
|
||||
"delay-explained": "El agente/servicio inicio recientemente y está retrasando el inicio de la instancia del servidor de Minecraft.",
|
||||
"host": "Host",
|
||||
"kill": "Matar Proceso",
|
||||
"killing": "Matando el proceso...",
|
||||
"killing": "Cerrando el proceso...",
|
||||
"lastBackup": "Último:",
|
||||
"max": "Max",
|
||||
"max": "Máx",
|
||||
"memUsage": "Uso de memoria",
|
||||
"motd": "MOTD",
|
||||
"newServer": "Crear nuevo Servidor",
|
||||
"nextBackup": "Próximo:",
|
||||
"no-servers": "Actualmente no hay servidores. Para comenzar, haga click",
|
||||
"no-servers": "Actualmente no hay servidores. Para comenzar, haga click en",
|
||||
"offline": "Desconectado",
|
||||
"online": "En línea",
|
||||
"players": "Jugadores",
|
||||
"restart": "Reiniciar",
|
||||
"sendingCommand": "Enviando tu comando",
|
||||
"server": "Server",
|
||||
"servers": "Servers",
|
||||
"server": "Servidor",
|
||||
"servers": "Servidores",
|
||||
"size": "Tamaño del directorio del servidor",
|
||||
"start": "Iniciar",
|
||||
"starting": "Inicio-retrasado",
|
||||
"status": "Estado",
|
||||
"stop": "Detener",
|
||||
"version": "Versión",
|
||||
"welcome": "Bienvenido a Crafty Controller"
|
||||
"welcome": "Bienvenido a Crafty Controller",
|
||||
"installing": "Instalando..."
|
||||
},
|
||||
"datatables": {
|
||||
"i18n": {
|
||||
"aria": {
|
||||
"sortAscending": ": activar para ordenar las columnas de masnera ascendente",
|
||||
"sortDescending": ": activar para ordenar las columnas de masnera descendente"
|
||||
"sortAscending": ": activar para ordenar las columnas de manera ascendente",
|
||||
"sortDescending": ": activar para ordenar las columnas de manera descendente"
|
||||
},
|
||||
"buttons": {
|
||||
"collection": "Colección <span class='ui-button-icon-primary ui-icon ui-icon-triangle-1-s'/>",
|
||||
"colvis": "Visibilidad de las columnas",
|
||||
"colvisRestore": "Restaurar visibilidad",
|
||||
"copy": "Copiar",
|
||||
"copyKeys": "Presiona ctrl o u2318 + C para copiar los datos de la tabla al portapapeles de tu sistema.<br><br>Para cancelar, click en este mensaje o presiona escape.",
|
||||
"copyKeys": "Presiona ctrl o u2318 + C para copiar los datos de la tabla al portapapeles de tu sistema.<br><br>Para cancelar, cliquea este mensaje o presiona escape.",
|
||||
"copySuccess": {
|
||||
"1": "Copiado 1 fila al portapapeles",
|
||||
"_": "Copiadas %d filas al portapapeles"
|
||||
"_": "Copiado %d filas al portapapeles"
|
||||
},
|
||||
"copyTitle": "Copiar al Portapapeles",
|
||||
"csv": "CSV",
|
||||
@ -128,15 +129,15 @@
|
||||
},
|
||||
"decimal": "",
|
||||
"emptyTable": "No hay datos disponibles en la tabla",
|
||||
"info": "Mostrando _START_ a _END_ de _TOTAL_ entradas",
|
||||
"infoEmpty": "Mostrando 0 a 0 de 0 entradas",
|
||||
"info": "Mostrando _START_ hasta _END_ de _TOTAL_ entradas",
|
||||
"infoEmpty": "Mostrando 0 de 0 entradas",
|
||||
"infoFiltered": "(filtrado de _MAX_ entradas totales)",
|
||||
"infoPostFix": "",
|
||||
"lengthMenu": "Mostrar _MENU_ entradas",
|
||||
"lengthMenu": "Mostrar entradas de _MENU_",
|
||||
"loadingRecords": "Cargando...",
|
||||
"paginate": {
|
||||
"first": "Primero",
|
||||
"last": "Ultimo",
|
||||
"last": "Último",
|
||||
"next": "Siguiente",
|
||||
"previous": "Anterior"
|
||||
},
|
||||
@ -160,26 +161,38 @@
|
||||
}
|
||||
},
|
||||
"thousands": ",",
|
||||
"zeroRecords": "No se encontraron registros coincidentes"
|
||||
"zeroRecords": "No se encontraron registros que coincidan"
|
||||
}
|
||||
},
|
||||
"error": {
|
||||
"closedPort": "Hemos detectado que el puerto {} podría no estar abierto en la red del host o un firewall lo está bloqueando. Las conexiones remotas de clientes al servidor podrían estar limitadas.",
|
||||
"contact": "Contacta el soporte de Crafty Control desde Discord",
|
||||
"embarassing": "Oh por, bueno, esto es vergonzoso.",
|
||||
"embarassing": "¡Oh cielos! Esto es embarazoso.",
|
||||
"error": "Error!",
|
||||
"eulaAgree": "Estás de acuerdo?",
|
||||
"eulaMsg": "Debes aceptar el EULA. Una copia del EULA de Minecraft esta vinculada debajo de este mensaje.",
|
||||
"eulaAgree": "¿Estás de acuerdo?",
|
||||
"eulaMsg": "Debes aceptar el ",
|
||||
"privMsg": "y el ",
|
||||
"eulaTitle": "Aceptar EULA",
|
||||
"fileTooLarge": "Subida fallida. Carga de archivo demasiado grande. Póngase en contacto con el administrador del sistema para obtener ayuda.",
|
||||
"agree": "Aceptar",
|
||||
"cancel": "Cancelar",
|
||||
"fileTooLarge": "Subida fallida. El archivo es demasiado grande. Contacte al administrador del sistema para obtener asistencia.",
|
||||
"hereIsTheError": "Aquí está el error.",
|
||||
"internet": "Hemos detectado que la maquina ejecutando Crafty no tiene acceso a internet. Las conexiones de clientes al servidor podrían estar limitadas.",
|
||||
"no-file": "No se puede localizar el archivo solicitado. Verifique dos veces la ruta. Capaz Crafty no tiene los permisos adecuados?",
|
||||
"noJava": "Server {} fallo al iniciar con código de error: Detectamos que Java no esta instalado, Por favor instale java y inicie el servidor.",
|
||||
"not-downloaded": "Parece que no podemos encontrar su archivo ejecutable. Capaz no ha terminado de descargarse o los permisos están configurados como ejecutables.",
|
||||
"portReminder": "Detectamos que es la primera vez que se inicia {}. Asegúrese de configurar el puerto {} A través de su router/firewall para hacer el servidor accesible.",
|
||||
"internet": "Hemos detectado que la máquina ejecutando Crafty no tiene acceso a internet. Las conexiones de cliente al servidor podrían ser limitadas.",
|
||||
"no-file": "No se puede encontrar el archivo solicitado. Verifique la dirección. ¿Quizas Crafty no tiene los permisos adecuados?",
|
||||
"noJava": "Servidor {} no pudo iniciarse: Detectamos que Java no está instalado, Por favor instale java e inicie el servidor.",
|
||||
"installerJava": "Fallo al instalar {} : La instalación de Forge requiere Java. Detectamos que Java no está instalado. Por favor instale java e inicie el servidor.",
|
||||
"not-downloaded": "No podemos encontrar el archivo ejecutable. ¿Ha terminado de descargarse? ¿Están los permisos puestos como ejecutable?",
|
||||
"portReminder": "Detectamos que es la primera vez que se inicia {}. Asegúrese de configurar el puerto {} a través de su router/firewall para hacer el servidor accesible por Internet.",
|
||||
"start-error": "Servidor {} fallo al iniciar con código de error: {}",
|
||||
"terribleFailure": "¡Un terrible error!"
|
||||
"terribleFailure": "¡Un terrible error!",
|
||||
"superError": "Debes ser un super usuario para completar esta acción.",
|
||||
"fileError": "El tipo de archivo debe ser una imagen.",
|
||||
"migration": "El almacenamiento del servidor principal de Crafty se está migrando a una nueva ubicación. El inicio de servidores se han suspendido durante este periodo. Espere mientras finalizamos esta migración.",
|
||||
"serverJars1": "API de Servidor JAR no disponible. por favor, compruebe",
|
||||
"bedrockError": "Descargas de Bedrock no disponibles. por favor, compruebe",
|
||||
"craftyStatus": "Página de estados de Crafty",
|
||||
"serverJars2": "para la información más actualizada.",
|
||||
"cronFormat": "Detectado formato CRON invalido",
|
||||
"noInternet": "Crafty tiene problemas para acceder a Internet. La creación del servidor ha sido deshabilitada. Verifique su conexión a Internet y actualice esta página.Crafty tiene problemas para acceder a Internet. La creación del servidor ha sido deshabilitada. Verifique su conexión a Internet y actualice esta página."
|
||||
},
|
||||
"footer": {
|
||||
"allRightsReserved": "Todos los derechos reservados",
|
||||
@ -194,97 +207,125 @@
|
||||
},
|
||||
"notify": {
|
||||
"activityLog": "Registros de actividad",
|
||||
"backupComplete": "Backup completado de manera exitosa en el servidor {}",
|
||||
"backupStarted": "Backup iniciado para el servidor {}",
|
||||
"downloadLogs": "Descargar registros de soporte?",
|
||||
"finishedPreparing": "Terminamos la preparación de tus registros de soporte. Por favor presione el boton para descargar.",
|
||||
"backupComplete": "Respaldo completado de manera exitosa para el servidor {}",
|
||||
"backupStarted": "Respaldo iniciado para el servidor {}",
|
||||
"downloadLogs": "¿Descargar registros de soporte?",
|
||||
"finishedPreparing": "Terminamos la preparación de tus registros de soporte. Por favor presione el botón para descargar.",
|
||||
"logout": "Cerrar Sesión",
|
||||
"preparingLogs": " Por favor espere mientras preparamos los registros. Le enviaremos una notificación cuando estén listos. Esto puede tomar un rato en implementaciones grandes.",
|
||||
"supportLogs": "Registros de soporte"
|
||||
},
|
||||
"offline": {
|
||||
"offline": "Desconectado",
|
||||
"pleaseConnect": "Conéctate a Internet para usar Crafty."
|
||||
},
|
||||
"panelConfig": {
|
||||
"adminControls": "Controles de administrador",
|
||||
"allowedServers": "Servidores Habilitados",
|
||||
"assignedRoles": "Roles asignados",
|
||||
"allowedServers": "Servidores Permitidos",
|
||||
"assignedRoles": "Grupos asignados",
|
||||
"cancel": "Cancelar",
|
||||
"clearComms": "Limpiar comandos sin ejecutar.",
|
||||
"select": "Seleccionar",
|
||||
"apply": "Aplicar",
|
||||
"delete": "Eliminar",
|
||||
"edit": "Editar",
|
||||
"enabled": "Habilitado",
|
||||
"newRole": "Agregar un nuevo rol",
|
||||
"match": "Las contraseñas deben coincidir",
|
||||
"newRole": "Agregar nuevo Grupo",
|
||||
"newUser": "Agregar nuevo Usuario",
|
||||
"pageTitle": "Configuración del panel",
|
||||
"role": "Rol",
|
||||
"roles": "Roles",
|
||||
"roleUsers": "Usuarios del rol",
|
||||
"role": "Grupo",
|
||||
"roles": "Grupos",
|
||||
"roleUsers": "Usuarios del Grupo",
|
||||
"save": "Guardar",
|
||||
"superConfirm": "Proceder solamente si queres que este usuario tenga acceso a TODO(todas las cuentas de usuarios, servidores, configuración del panel, etc...) Hasta puede quitarte tu permiso de superuser.",
|
||||
"superConfirmTitle": "Habilitar superusers? Estas seguro?",
|
||||
"superConfirm": "Proceder solamente si quieres que este usuario tenga acceso a TODO (todas las cuentas de usuarios, servidores, configuración del panel, etc.) Hasta puede quitarte tu permiso de super usuario.",
|
||||
"superConfirmTitle": "¿Activar super usuario? ¿Seguro?",
|
||||
"user": "Usuario",
|
||||
"users": "Usuarios"
|
||||
"users": "Usuarios",
|
||||
"title": "Configuración de Crafty",
|
||||
"enableLang": "Activar todos los Idiomas",
|
||||
"noMounts": "No mostrar Montajes en panel de Control",
|
||||
"globalServer": "Directorio Global de Servidores",
|
||||
"globalExplain": "Donde Crafty almacena todos los archivos de tu servidor. (Juntaremos la ruta con /servers/[uuid de servidor])"
|
||||
},
|
||||
"customLogin": {
|
||||
"customLoginPage": "Personalizar la página de logueo",
|
||||
"loginImage": "Subir una imagen de fondo para la pantalla de logueo.",
|
||||
"labelLoginImage": "Elige tu fondo para la pantalla de logueo",
|
||||
"backgroundUpload": "Subir imagen de fondo",
|
||||
"loginBackground": "Imagen de fondo de logueo",
|
||||
"loginOpacity": "Seleccionar la opacidad de la ventana de logueo",
|
||||
"select": "Seleccionar",
|
||||
"apply": "Aplicar",
|
||||
"delete": "Eliminar",
|
||||
"selectImage": "Seleccionar una imagen",
|
||||
"preview": "Previsualizar",
|
||||
"pageTitle": "Página de logueo personalizada"
|
||||
},
|
||||
"rolesConfig": {
|
||||
"config": "Configuracion de roles",
|
||||
"configDesc": "Aca podes cambiar la configuracion de los roles",
|
||||
"config": "Configuración de grupos",
|
||||
"configDesc": "Aquí puedes cambiar la configuración de los grupos",
|
||||
"configUpdate": "Actualizado: ",
|
||||
"created": "Creado: ",
|
||||
"delRole": "Eliminar Rol",
|
||||
"doesNotExist": "No podes elminiar algo que todavia no existe",
|
||||
"pageTitle": "Editar Rol",
|
||||
"pageTitleNew": "Nuevo Rol",
|
||||
"permAccess": "Acceso?",
|
||||
"permName": "Nombre de los permisos",
|
||||
"permsServer": "Permisos que tiene este rol para esos servidores específicos.",
|
||||
"roleConfigArea": "Zona de configuración de roles",
|
||||
"roleDesc": "Como te gustaria llamar a este rol?",
|
||||
"roleName": "Nombre del rol: ",
|
||||
"rolePerms": "Permisos del rol",
|
||||
"roleServers": "Servidores Habilitados",
|
||||
"roleTitle": "Configuración de Roles",
|
||||
"delRole": "Eliminar Grupo",
|
||||
"doesNotExist": "No puedes eliminar algo que todavía no existe",
|
||||
"pageTitle": "Editar Grupo",
|
||||
"pageTitleNew": "Nuevo Grupo",
|
||||
"permAccess": "¿Acceso?",
|
||||
"permName": "Nombre del permiso",
|
||||
"permsServer": "Permisos que tiene este grupo para los servidores especificados.",
|
||||
"roleConfigArea": "Área de configuración de grupos",
|
||||
"roleDesc": "¿Como te gustaría llamar a este grupo?",
|
||||
"roleName": "Nombre del grupo: ",
|
||||
"rolePerms": "Permisos del grupo",
|
||||
"roleServers": "Servidores Permitidos",
|
||||
"roleTitle": "Configuración de Grupos",
|
||||
"roleUserName": "Nombre de usuario",
|
||||
"roleUsers": "Usuarios del rol: ",
|
||||
"serverAccess": "Acceso?",
|
||||
"roleUsers": "Usuarios del grupo: ",
|
||||
"serverAccess": "¿Acceso?",
|
||||
"serverName": "Nombre del servidor",
|
||||
"serversDesc": "Servidores a los que este rol puede acceder"
|
||||
"serversDesc": "Servidores a los que este grupo puede acceder"
|
||||
},
|
||||
"serverBackups": {
|
||||
"backupAtMidnight": "¿Copia de seguridad automática a medianoche?",
|
||||
"backupNow": "¡Haga una copia de seguridad ahora!",
|
||||
"backupNow": "¡Respalde ahora!",
|
||||
"backupTask": "Se ha iniciado una tarea de copia de seguridad.",
|
||||
"cancel": "Cancelar",
|
||||
"clickExclude": "Click para seleccionar las Exclusiones",
|
||||
"compress": "Comprimir el Backup",
|
||||
"compress": "Comprimir la copia",
|
||||
"confirm": "Confirmar",
|
||||
"confirmDelete": "¿Quieres eliminar esta copia de seguridad? Esto no se puede deshacer.",
|
||||
"confirmRestore": "Esta seguro de que quiere restaurar desde este backup. Todos los archivos actuales del servidor seran cambiados al estado del backup y seran irrecuperables.",
|
||||
"confirmRestore": "¿Seguro que quiere restaurar desde este respaldo?. Todos los archivos del servidor actuales serán cambiados al estado del respaldo y serán irrecuperables.",
|
||||
"currentBackups": "Copias de seguridad actuales",
|
||||
"delete": "Eliminar",
|
||||
"destroyBackup": "¿Destruir copia de seguridad \" + file_to_del + \"?",
|
||||
"download": "Descargar",
|
||||
"excludedBackups": "Rutas Excluidas: ",
|
||||
"excludedChoose": "Elija las rutas que desea excluir de sus backups",
|
||||
"exclusionsTitle": "Exclusiones del backup.",
|
||||
"maxBackups": "Máxima cantidad de Copias de seguridad",
|
||||
"maxBackupsDesc": "Crafty no almacenará más de N copias de seguridad, eliminando la más antigua (Ingrese 0 para mantenerlas todas)",
|
||||
"excludedChoose": "Elige las rutas que desea excluir de los respaldos",
|
||||
"exclusionsTitle": "Exclusiones en respaldos.",
|
||||
"maxBackups": "Cantidad máxima de respaldos",
|
||||
"maxBackupsDesc": "Crafty no almacenará más de N copias de seguridad, eliminando la más antigua. (Sin límite: 0)",
|
||||
"options": "Opciones",
|
||||
"path": "Dirección",
|
||||
"path": "Ruta",
|
||||
"restore": "Restaurar",
|
||||
"restoring": "Restaurando copia de seguridad. Esto puede tomar un tiempo. Sea paciente.",
|
||||
"save": "Guardar",
|
||||
"shutdown": "Apague el servidor durante la duración de la copia del backup.",
|
||||
"shutdown": "Apagar el servidor durante la duración de la copia del respaldo.",
|
||||
"size": "Tamaño",
|
||||
"storageLocation": "Ubicación de almacenamiento",
|
||||
"storageLocationDesc": "¿Dónde quieres almacenar las copias de seguridad?"
|
||||
"storageLocationDesc": "¿Dónde quieres almacenar las copias de seguridad?",
|
||||
"before": "Comando ejecutado antes del respaldo",
|
||||
"after": "Comando ejecutado después del respaldo"
|
||||
},
|
||||
"serverConfig": {
|
||||
"bePatientDelete": "Tenga paciencia mientras eliminamos su servidor del panel de Crafty. Esta pantalla se cerrará en unos momentos.",
|
||||
"bePatientDeleteFiles": "Tenga paciencia mientras eliminamos su servidor del panel de Crafty y eliminamos todos los archivos. Esta pantalla se cerrará en unos momentos.",
|
||||
"bePatientUpdate": "Tenga paciencia mientras actualizamos el servidor. El tiempo de descarga puede variar según la velocidad del Internet...<br /> Esta pantalla se actualizará en unos momentos.",
|
||||
"cancel": "Cancelar",
|
||||
"crashTime": "Tiempo de espera por crash",
|
||||
"crashTimeDesc": "Cuanto tiempo se debe esperar después de que crafty considere su servidor como crasheado?",
|
||||
"deleteFilesQuestion": "¿Eliminar archivos del servidor de la máquina?",
|
||||
"deleteFilesQuestionMessage": "¿Le gustaría que Crafty elimine todos los archivos del servidor de la máquina host? <br><br><strong>Esto incluye backups del servidor.</strong>",
|
||||
"crashTime": "Tiempo de espera por crasheo",
|
||||
"crashTimeDesc": "¿Cuanto tiempo esperar para considerar el servidor como crasheado?",
|
||||
"deleteFilesQuestion": "¿Eliminar archivos del servidor del host?",
|
||||
"deleteFilesQuestionMessage": "¿Le gustaría que Crafty elimine todos los archivos del servidor de la máquina host? <br><br><strong>Esto incluye respaldos del servidor.</strong>",
|
||||
"deleteServer": "Eliminar Servidor",
|
||||
"deleteServerQuestion": "¿Eliminar Servidor?",
|
||||
"deleteServerQuestionMessage": "¿Estás seguro de que desea eliminar este servidor? Después de esto no hay vuelta atrás...",
|
||||
@ -292,79 +333,91 @@
|
||||
"exeUpdateURLDesc": "URL de descarga directa para actualizaciones.",
|
||||
"javaNoChange": "No sobrescribir",
|
||||
"javaVersion": "Sobrescribir versión de Java.",
|
||||
"javaVersionDesc": "Si vas a sobrescribir la versión de Java, Asegúrese de que ponga la localizacion de java con ' ' (comillas).",
|
||||
"javaVersionDesc": "Si vas a sobrescribir la versión de Java, Asegúrese de rodear la ubicación con comillas. (Variable predeterminada 'java' excluida)",
|
||||
"noDelete": "No, vuelve atrás.",
|
||||
"noDeleteFiles": "No, solo remover del panel.",
|
||||
"removeOldLogsAfter": "Eliminar registros antiguos después de",
|
||||
"removeOldLogsAfterDesc": "¿Cuántos días debe ser un archivo de registro para ser eliminado (0 es desactivado)?",
|
||||
"removeOldLogsAfterDesc": "¿Cuántos días debe tener un archivo de registro para ser eliminado? (Desactivar: 0)",
|
||||
"save": "Guardar",
|
||||
"sendingDelete": "Eliminando servidor",
|
||||
"sendingRequest": "Enviando tu solicitud...",
|
||||
"serverAutoStart": "Inicio automático del servidor",
|
||||
"serverAutostartDelay": "Retraso del inicio automático del servidor.",
|
||||
"serverAutostartDelayDesc": "Tiempo de retraso antes del inicio automático (si está habilitado debajo)",
|
||||
"serverAutostartDelayDesc": "Tiempo de retraso antes del inicio automático (Si está habilitado debajo)",
|
||||
"serverCrashDetection": "Detección de crasheos del Servidor",
|
||||
"serverExecutable": "Ejecutable del servidor",
|
||||
"serverExecutableDesc": "El archivo ejecutable del servidor.",
|
||||
"serverExecutionCommand": "Comando de ejecución del Servidor",
|
||||
"serverExecutionCommandDesc": "Se ejecutara en una terminal oculta para iniciar el servidor.",
|
||||
"serverIP": "Server IP",
|
||||
"serverIPDesc": "IP a la que Crafty debería conectarse para obtener estadísticas (pruebe con una ip real en lugar de 127.0.0.1 si tienes problemas)",
|
||||
"serverExecutionCommandDesc": "Se ejecutará en una terminal oculta para iniciar el servidor.",
|
||||
"serverIP": "IP del Servidor",
|
||||
"serverIPDesc": "IP a la que Crafty debería conectarse para obtener estadísticas (Pruebe con una IP real en lugar de 127.0.0.1 si tienes problemas)",
|
||||
"serverLogLocation": "Ubicación del registro del servidor",
|
||||
"serverLogLocationDesc": "Dirección absoluta al archivo de registro",
|
||||
"serverLogLocationDesc": "Ruta absoluta al archivo de registro",
|
||||
"serverName": "Nombre del servidor",
|
||||
"serverNameDesc": "¿Cómo quieres nombrar el servidor?",
|
||||
"serverPath": "Directorio de trabajo del servidor",
|
||||
"serverPathDesc": "Dirección absoluta del servidor (sin incluir el ejecutable)",
|
||||
"serverPath": "Ruta de trabajo del servidor",
|
||||
"serverPathDesc": "Ruta absoluta del servidor (sin incluir el ejecutable)",
|
||||
"serverPort": "Puerto del Servidor",
|
||||
"serverPortDesc": "Puerto al que Crafty debería conectarse para obtener estadísticas",
|
||||
"serverStopCommand": "Comando de detención del Servidor",
|
||||
"serverStopCommandDesc": "Comando que enviar al programa para detener el servidor.",
|
||||
"stopBeforeDeleting": "Detenga el servidor antes de eliminarlo.",
|
||||
"showStatus": "Mostrar en la pagina de estados publicos",
|
||||
"stopBeforeDeleting": "Por favor, detenga el servidor antes de eliminarlo.",
|
||||
"update": "Actualizar Ejecutable",
|
||||
"yesDelete": "Si, borralo.",
|
||||
"yesDeleteFiles": "Si, borra los archivos."
|
||||
"yesDelete": "Sí, borralo.",
|
||||
"yesDeleteFiles": "Sí, borra los archivos.",
|
||||
"shutdownTimeout": "Tiempo de espera al apagar",
|
||||
"timeoutExplain1": "Cuánto tiempo esperará Crafty a que su servidor se apague después de ejecutar el",
|
||||
"timeoutExplain2": "comando antes de forzar cerrar el proceso.",
|
||||
"statsHint1": "El puerto que ejecuta su servidor debe ir aquí. Crafty abre una conexión a su servidor para obtener estadísticas.",
|
||||
"statsHint2": "Esto no cambia el puerto de su servidor. Aún debe cambiar el puerto en el archivo de configuración de su servidor.",
|
||||
"ignoredExits": "Codigos de salida al crashear ignorados",
|
||||
"ignoredExitsExplain": "Codigos de salida que Crafty deberia ignorar como un 'apagado' normal (separarados por comas)"
|
||||
},
|
||||
"serverConfigHelp": {
|
||||
"desc": "Here is where you can change the configuration of your server",
|
||||
"desc": "Aquí es donde puede cambiar la configuración de su servidor",
|
||||
"perms": [
|
||||
"It is recommended to <code>NOT</code> change the paths of a server managed by Crafty.",
|
||||
"Changing paths <code>CAN</code> break things, especially on Linux type operating systems where file permissions are more locked down.",
|
||||
"Se recomienda <code>NO</code> cambiar las rutas de un servidor administrado por Crafty.",
|
||||
"Cambiar las rutas <code>PUEDE</code> romper cosas, especialmente en sistemas operativos tipo Linux donde los permisos de archivo están más bloqueados.",
|
||||
"<br /><br/>",
|
||||
"If you feel you have to change a where a server is located you may do so as long as you give the \"crafty\" user permission to read / write to the server path.",
|
||||
"Si cree que tiene que cambiar la ubicación de un servidor, puede hacerlo siempre que le dé permiso al usuario \"Crafty\" para leer/escribir en la ruta del servidor.",
|
||||
"<br />",
|
||||
"<br />",
|
||||
"On Linux this is best done by executing the following:<br />",
|
||||
"En Linux, esto se hace mejor ejecutando lo siguiente:<br />",
|
||||
"<code>",
|
||||
" sudo chown crafty:crafty /path/to/your/server -R<br />",
|
||||
" sudo chmod 2775 /path/to/your/server -R<br />",
|
||||
" sudo chown crafty:crafty /ruta/del/servidor -R<br />",
|
||||
" sudo chmod 2775 /ruta/del/servidor -R<br />",
|
||||
"</code>"
|
||||
],
|
||||
"title": "Server Config Area"
|
||||
"title": "Área de configuración del servidor"
|
||||
},
|
||||
"serverDetails": {
|
||||
"backup": "Backup",
|
||||
"backup": "Respaldos",
|
||||
"config": "Configuración",
|
||||
"files": "Archivos",
|
||||
"logs": "Registros",
|
||||
"playerControls": "Gestionar jugadores",
|
||||
"schedule": "Programación Tareas",
|
||||
"schedule": "Programar Tareas",
|
||||
"serverDetails": "Detalles del Servidor",
|
||||
"terminal": "Terminal"
|
||||
"terminal": "Terminal",
|
||||
"metrics": "Métricas",
|
||||
"reset": "Reiniciar Desplazamiento",
|
||||
"filter": "Filtrar Registros",
|
||||
"filterList": "Palabras filtradas"
|
||||
},
|
||||
"serverFiles": {
|
||||
"clickUpload": "Click aquí para seleccionar tus archivos",
|
||||
"close": "Cerrar",
|
||||
"createDir": "Crear directorio",
|
||||
"createDirQuestion": "Que nombre quiere darle al nuevo directorio?",
|
||||
"createDirQuestion": "¿Que nombre quieres para el nuevo directorio?",
|
||||
"createFile": "Crear archivo",
|
||||
"createFileQuestion": "Que nombre quiere darle al nuevo archivo?",
|
||||
"createFileQuestion": "¿Que nombre quieres para el nuevo archivo?",
|
||||
"default": "Predeterminado",
|
||||
"delete": "Eliminar",
|
||||
"deleteItemQuestion": "¿Estás seguro de que quieres eliminar \" + name + \"?",
|
||||
"deleteItemQuestionMessage": "¡Estas eliminando \\\"\" + path + \"\\\"!<br/><br/>¡Esta acción será irreversible y se perderá para siempre!",
|
||||
"download": "Descargar",
|
||||
"editingFile": "Editar archivo",
|
||||
"editingFile": "Editando archivo",
|
||||
"error": "Error al encontrar archivos",
|
||||
"fileReadError": "Error de lectura del archivo",
|
||||
"files": "Archivos",
|
||||
@ -373,16 +426,16 @@
|
||||
"noDelete": "No",
|
||||
"noscript": "El administrador de archivos no funciona sin JavaScript",
|
||||
"rename": "Renombrar",
|
||||
"renameItemQuestion": "Cuál debería ser el nuevo nombre?",
|
||||
"renameItemQuestion": "¿Cuál debería ser el nuevo nombre?",
|
||||
"save": "Guardar",
|
||||
"size": "Alternar tamaño del editor.",
|
||||
"stayHere": "NO SALGA DE ESTA PÁGINA",
|
||||
"unsupportedLanguage": "Advertencia: este no es un tipo de archivo admitido",
|
||||
"stayHere": "¡NO SALGA DE ESTA PÁGINA!",
|
||||
"unsupportedLanguage": "Advertencia: Este no es un tipo de archivo admitido",
|
||||
"unzip": "Descomprimir (UnZip)",
|
||||
"upload": "Subir",
|
||||
"uploadTitle": "Subir archivos a: ",
|
||||
"waitUpload": "Espera mientras subimos tus archivos... Esto puede tomar un tiempo.",
|
||||
"yesDelete": "Si, entiendo las consecuencias"
|
||||
"yesDelete": "Sí, entiendo las consecuencias"
|
||||
},
|
||||
"serverPlayerManagement": {
|
||||
"bannedPlayers": "Jugadores Baneados",
|
||||
@ -390,39 +443,57 @@
|
||||
"players": "Jugadores"
|
||||
},
|
||||
"serverScheduleConfig": {
|
||||
"backup": "Backup del Servidor",
|
||||
"backup": "Respaldar Servidor",
|
||||
"select": "Básico, / Cron / En cadena",
|
||||
"basic": "Básico",
|
||||
"children": "Tareas 'hijos' enlazados: ",
|
||||
"command": "Comando",
|
||||
"command-explain": "Que comandó quiere que sea ejecutado, no incluya el '/'",
|
||||
"cron": "Cron",
|
||||
"cron-explain": "Ponga su configuración de cron. -- NOTA: Pagina recomendada: 'https://crontab.guru'",
|
||||
"custom": "Comando Customizado",
|
||||
"cron-explain": "Ponga su cadena de CRON. -- NOTA: Página recomendada: 'https://crontab.guru'",
|
||||
"custom": "Comando Personalizado",
|
||||
"days": "Días",
|
||||
"enabled": "Habilitado",
|
||||
"hours": "Horas",
|
||||
"interval": "Intervalo",
|
||||
"interval-explain": "Con qué frecuencia quieres que se ejecute esta tarea?",
|
||||
"interval-explain": "¿Con qué frecuencia quieres que se ejecute esta tarea?",
|
||||
"minutes": "Minutos",
|
||||
"offset": "Retraso",
|
||||
"offset-explain": "Cuanto tiempo se debe esperar para ejecutar esta tarea después de la primera? (En Segundos).",
|
||||
"one-time": "Borrar después de su ejecución?",
|
||||
"offset-explain": "¿Cuanto tiempo se debe esperar para ejecutar esta tarea después de la primera? (En Segundos).",
|
||||
"one-time": "¿Borrar después de su ejecución?",
|
||||
"parent": "Seleccione una tarea programada 'padre'",
|
||||
"parent-explain": "Qué tarea programada debería activar esta?",
|
||||
"reaction": "Reaccion",
|
||||
"parent-explain": "¿Qué tarea programada debería activar esta?",
|
||||
"reaction": "Reacción",
|
||||
"restart": "Reiniciar el Servidor",
|
||||
"start": "Iniciar el Servidor",
|
||||
"stop": "Apagar el Servidor",
|
||||
"time": "Horario",
|
||||
"time-explain": "A que hora quiere que la tarea programada se ejecute?"
|
||||
"time-explain": "¿A que hora quiere que la tarea programada se ejecute?"
|
||||
},
|
||||
"serverSchedules": {
|
||||
"areYouSure": "Borrar tarea programada?",
|
||||
"scheduledTasks": "Tareas programadas",
|
||||
"create": "Crear nueva tarea programada",
|
||||
"name": "Nombre",
|
||||
"action": "Acción",
|
||||
"command": "Comando",
|
||||
"interval": "Intervalo",
|
||||
"nextRun": "Siguiente ejecución",
|
||||
"enabled": "Habilitado",
|
||||
"edit": "Editar",
|
||||
"every": "Cada",
|
||||
"yes": "Sí",
|
||||
"no": "No",
|
||||
"cron": "Cadena CRON",
|
||||
"details": "Detalles de la tarea",
|
||||
"child": "Tarea hija con ID ",
|
||||
"areYouSure": "¿Borrar tarea programada?",
|
||||
"close": "Cerrar",
|
||||
"delete": "Eliminar",
|
||||
"cancel": "Cancelar",
|
||||
"cannotSee": "No puede pude ver todo?",
|
||||
"cannotSeeOnMobile": "Intente hacer clic en una tarea programada para obtener todos los detalles.",
|
||||
"cannotSee": "¿No puede ver todo?",
|
||||
"cannotSeeOnMobile": "Intente hacer click en una tarea programada para obtener todos los detalles.",
|
||||
"confirm": "Confirmar",
|
||||
"confirmDelete": "Estás seguro de que desea eliminar esta tarea programada? Esto no se puede deshacer."
|
||||
"confirmDelete": "¿De verdad desea eliminar esta tarea programada? Esto no se puede deshacer."
|
||||
},
|
||||
"serverStats": {
|
||||
"cpuUsage": "Uso de CPU",
|
||||
@ -443,32 +514,40 @@
|
||||
},
|
||||
"serverTerm": {
|
||||
"commandInput": "Introducir tu comando",
|
||||
"delay-explained": "El agente/servicio ha recientemente iniciado y está retrasando el inicio de la instancia del servidor de Minecraft.",
|
||||
"delay-explained": "El agente/servicio se inicio recientemente y está retrasando iniciar la instancia del servidor de Minecraft.",
|
||||
"downloading": "Descargando...",
|
||||
"restart": "Reiniciar",
|
||||
"sendCommand": "Enviar comando",
|
||||
"start": "Iniciar",
|
||||
"starting": "Inicio-retrasado",
|
||||
"stop": "Detener",
|
||||
"stopScroll": "Detener Scrolling automatico",
|
||||
"updating": "Actualizando..."
|
||||
"stopScroll": "Detener Desplazamiento automático",
|
||||
"updating": "Actualizando...",
|
||||
"installing": "Instalando..."
|
||||
},
|
||||
"serverMetrics": {
|
||||
"resetZoom": "Reiniciar Zoom",
|
||||
"zoomHint1": "Para hacer zoom en el gráfico, mantén presionada la tecla shift y luego usa la rueda de desplazamiento.",
|
||||
"zoomHint2": "Alternativamente, mantén presionada la tecla shift, luego haz click y arrastra el área en la que deseas hacer zoom."
|
||||
},
|
||||
"serverWizard": {
|
||||
"absoluteServerPath": "Dirección absoluta del servidor",
|
||||
"absoluteZipPath": "Dirección absoluta del servidor",
|
||||
"addRole": "Añadir Servidor a grupos existentes..",
|
||||
"autoCreate": "Si no se selecciona ninguno, ¡Crafty creara uno!",
|
||||
"bePatient": "Por favor tenga paciencia, ya que estamos ' + (importing ? 'import' : 'download') + ' el servidor.",
|
||||
"buildServer": "Construir Servidor!",
|
||||
"absoluteServerPath": "Ruta absoluta del servidor",
|
||||
"absoluteZipPath": "Ruta absoluta servidor",
|
||||
"addRole": "Añadir Servidor a grupos existentes...",
|
||||
"autoCreate": "Si ninguno es seleccionado, ¡Crafty creara uno!",
|
||||
"bePatient": "Por favor tenga paciencia, mientras se ' + (importing ? 'importa' : 'descarga') + ' el servidor.",
|
||||
"buildServer": "¡Crear Servidor!",
|
||||
"clickRoot": "Click aquí para seleccionar el directorio raiz.",
|
||||
"close": "Cerrar",
|
||||
"defaultPort": "25565 (Por defecto)",
|
||||
"downloading": "Descargando Servidor...",
|
||||
"explainRoot": "Por favor, haga click en el botón de abajo para seleccionar el directorio raiz de su servidor.",
|
||||
"explainRoot": "Por favor, haga click en el botón debajo para seleccionar el directorio raíz de su servidor.",
|
||||
"importing": "Importando Servidor...",
|
||||
"importServer": "Importar Servidor existente",
|
||||
"importServerButton": "Importar Servidor!",
|
||||
"importServerButton": "¡Importar Servidor!",
|
||||
"importZip": "Importar desde archivo Zip",
|
||||
"uploadZip": "Subir archivo Zip para importar servidor",
|
||||
"labelZipFile": "Elige tu archivo Zip",
|
||||
"maxMem": "Memoria máxima",
|
||||
"minMem": "Memoria mínima",
|
||||
"myNewServer": "Mi nuevo Servidor",
|
||||
@ -479,62 +558,68 @@
|
||||
"save": "Guardar",
|
||||
"selectRole": "Seleccionar Grupo(s)",
|
||||
"selectRoot": "Seleccione el directorio raíz del archivo.",
|
||||
"selectType": "Selecciona un tipo",
|
||||
"selectType": "Tipo de servidor (Vanilla, Modificado, Mods, etc.)",
|
||||
"selectVersion": "Selecciona una versión",
|
||||
"selectZipDir": "Seleccione el directorio donde quiere que se extraigan los archivos.",
|
||||
"selectZipDir": "Seleccione el directorio del archivo que quiere extraer el contenido.",
|
||||
"serverJar": "Archivo Jar del servidor",
|
||||
"serverName": "Nombre del servidor",
|
||||
"serverPath": "Dirección del servidor",
|
||||
"serverPath": "Ruta del servidor",
|
||||
"serverPort": "Puerto del servidor",
|
||||
"serverType": "Tipo de servidor",
|
||||
"serverVersion": "Versión del servidor",
|
||||
"serverUpload": "Subir servidor comprimido",
|
||||
"sizeInGB": "Tamaño en GB",
|
||||
"zipPath": "Dirección del servidor"
|
||||
"uploadButton": "Subir",
|
||||
"zipPath": "Ruta del servidor"
|
||||
},
|
||||
"sidebar": {
|
||||
"contribute": "Contribuir",
|
||||
"credits": "Creditos",
|
||||
"credits": "Créditos",
|
||||
"dashboard": "Panel de control",
|
||||
"documentation": "Documentación",
|
||||
"navigation": "Navegación",
|
||||
"newServer": "Crear nuevo Servidor",
|
||||
"servers": "Servers"
|
||||
"servers": "Servidores",
|
||||
"inApp": "Documentación de la Aplicación"
|
||||
},
|
||||
"userConfig": {
|
||||
"apiKey": "Claves API",
|
||||
"auth": "Autorizado? ",
|
||||
"auth": "¿Autorizado? ",
|
||||
"config": "Configuración",
|
||||
"configArea": "Area de Configuracion de Usuarios",
|
||||
"configAreaDesc": "Aca modificas la configuración de todos tus usuarios.",
|
||||
"confirmDelete": "Está seguro de que quiere borrar a este usuario? Esta acción es irreversible.",
|
||||
"configArea": "Área de Configuración de Usuario",
|
||||
"configAreaDesc": "Aquí modificas la configuración de este usuario.",
|
||||
"confirmDelete": "¿Está seguro de que quiere eliminar a este usuario? Esta acción es irreversible.",
|
||||
"craftyPermDesc": "Permisos de Crafty que tiene este usuario.",
|
||||
"craftyPerms": "Permisos de Crafty: ",
|
||||
"created": "Creado: ",
|
||||
"deleteUser": "Borrar Usuario: ",
|
||||
"deleteUserB": "Borrar Usuario",
|
||||
"delSuper": "No puedes borrar un super user",
|
||||
"deleteUser": "Eliminar Usuario: ",
|
||||
"deleteUserB": "Eliminar Usuario",
|
||||
"delSuper": "No puedes eliminar un super usuario",
|
||||
"enabled": "Habilitado",
|
||||
"gravDesc": "Este mail se va a usar solamente para conseguir el Gravatar. Crafty no va a usar esta información bajo ninguna circunstancia más que para conseguir el Gravatar™",
|
||||
"gravDesc": "Este mail será utilizado únicamente para obtener el Gravatar. Crafty no utilizará esta información bajo otra circunstancia aparte de obtener el Gravatar™",
|
||||
"gravEmail": "Gravatar™ Email",
|
||||
"lastIP": "Ultima IP: ",
|
||||
"lastIP": "Última IP: ",
|
||||
"lastLogin": "Última Sesión: ",
|
||||
"lastUpdate": "Última Actualización: ",
|
||||
"leaveBlank": "Para editar el usuario sin cambiar la contraseña, no completar nada.",
|
||||
"member": "Miembro?",
|
||||
"notExist": "No se puede borrar algo que no existe!",
|
||||
"leaveBlank": "Para editar el usuario sin cambiar la contraseña, dejar en blanco.",
|
||||
"member": "¿Miembro?",
|
||||
"notExist": "¡No se puede eliminar algo que no existe!",
|
||||
"pageTitle": "Editar Usuario.",
|
||||
"pageTitleNew": "Crear Usuario.",
|
||||
"password": "Nueva Contraseña",
|
||||
"permName": "Nombre del Permiso",
|
||||
"repeat": "Repita la contraseña.",
|
||||
"roleName": "Nombre del rol.",
|
||||
"super": "Super User",
|
||||
"roleName": "Nombre del grupo.",
|
||||
"super": "Super Usuario",
|
||||
"userLang": "Idioma del usuario.",
|
||||
"userTheme": "Tema de Interfaz",
|
||||
"userName": "Nombre de usuario.",
|
||||
"userNameDesc": "Como quieres llamar a este usuario?",
|
||||
"userRoles": "Roles del usuario.",
|
||||
"userRolesDesc": "Roles que tiene este usuario.",
|
||||
"userSettings": "Configuracion de Usuario.",
|
||||
"uses": "Número de usos habilitados. (-1 == sin límite)."
|
||||
"userNameDesc": "¿Como quieres llamar a este usuario?",
|
||||
"userRoles": "Grupos del usuario.",
|
||||
"userRolesDesc": "Grupos a los que este usuario pertenece.",
|
||||
"userSettings": "Configuración de Usuario.",
|
||||
"uses": "Número de usos permitidos. (Sin límite: -1)",
|
||||
"manager": "Administrador",
|
||||
"selectManager": "Seleccionar Administrador para Usuario"
|
||||
}
|
||||
}
|
@ -53,6 +53,20 @@
|
||||
"translationTitle": "Język tłumaczenia",
|
||||
"translator": "Tłumacze"
|
||||
},
|
||||
"customLogin": {
|
||||
"apply": "Apply",
|
||||
"backgroundUpload": "Załącz tło",
|
||||
"customLoginPage": "Dostosuj stronę zalogowania",
|
||||
"delete": "Usuń",
|
||||
"labelLoginImage": "Wybierz swoje tło logowania",
|
||||
"loginBackground": "Zdjęcie tła logowania",
|
||||
"loginImage": "Prześlij tło dla ekranu logowania.",
|
||||
"loginOpacity": "Wybierz przeźroczystość tła na ekranie logowania",
|
||||
"pageTitle": "Własna strona logowania",
|
||||
"preview": "Podgląd",
|
||||
"select": "Zaznacz",
|
||||
"selectImage": "Zaznacz zdjęcie"
|
||||
},
|
||||
"dashboard": {
|
||||
"actions": "Akcje",
|
||||
"allServers": "Wszystkie serwery",
|
||||
@ -75,6 +89,7 @@
|
||||
"dashboard": "Dashboard",
|
||||
"delay-explained": "Crafty niedawno się odpalił, właczanie serwera będzie trochę opóźnione",
|
||||
"host": "Host",
|
||||
"installing": "Instalowanie...",
|
||||
"kill": "Zabij proces",
|
||||
"killing": "Zabijanie procesu...",
|
||||
"lastBackup": "Ostatni:",
|
||||
@ -164,20 +179,33 @@
|
||||
}
|
||||
},
|
||||
"error": {
|
||||
"agree": "Zgadzam się",
|
||||
"bedrockError": "Pobieranie serwera bedrock jest teraz niedostępne. Proszę sprawdź",
|
||||
"cancel": "Anuluj",
|
||||
"contact": "Podrzebujesz pomocy? Zapraszamy na serwer discord Crafty Controler",
|
||||
"craftyStatus": "Status strony Craftyiego",
|
||||
"cronFormat": "Nieprawidłowy format Cron",
|
||||
"embarassing": "Oh, więc, to jest żenujące.",
|
||||
"error": "Błąd!",
|
||||
"eulaAgree": "Czy się zgadzasz?",
|
||||
"eulaMsg": "Musisz się zgodzić na EULA. Kopia EULA Minecraft jest zalinkowana pod tą wiadomością.",
|
||||
"eulaTitle": "Zgódź się na EULA",
|
||||
"fileError": "Plik musi być zdjęciem.",
|
||||
"fileTooLarge": "Upload nie udany. Plik jest za duży. Skontaktuj się z administratorem dla pomocy.",
|
||||
"hereIsTheError": "Tu jest problem",
|
||||
"installerJava": "Nie udało się zainstalować {} : Serwery Forge wymagają Java. Wykryliśmy że Java nie jest zainstalowana. Proszę zainstaluj Javę a następnie serwer.",
|
||||
"internet": "Zauważyliśmy że Crafty nie ma dostępu do internetu. Połączenie klientów z Craftym może być utrudnione.",
|
||||
"migration": "Miejsce przechowywania serwerów zostało zmienione w Craftym. Włączanie serwerów zostanie zawieszone do zakończenia migracji",
|
||||
"no-file": "Nie możemy znaleść żądanego pliku. Sprawdź ścieżkę. Czy Crafty ma odpowiednie uprawnienia?",
|
||||
"noInternet": "Crafty ma problem połączenia się z internetem. Tworzenie serwerów zostało wyłączone. Sprawdź swoje połączenie z intenetem i spróbuj ponownie.",
|
||||
"noJava": "Serwer {} nie mógł się odpalić z powodu: Zauważyliśmy że Java nie jest zainstalowana. Proszę zainstaluj Javę, a następnie włącz serwer.",
|
||||
"not-downloaded": "Nie możemy znaleść twojego pliku serwera. Czy skończył się pobierać? Czy permisje są ustawione na wykonywanle?",
|
||||
"portReminder": "Zauważyliśmy że to jest pierwszy raz {} kiedy był włączony. Upewnij się że otworzyłeś port {} na swoim routerze/firewallu aby korzystać z tego poza domem.",
|
||||
"privMsg": "i także ",
|
||||
"serverJars1": "API Server Jars jest niedostępne. Proszę sprawdź",
|
||||
"serverJars2": "dla najnowzsych informacji.",
|
||||
"start-error": "Serwer {} nie mógł się odpalić z powodu: {}",
|
||||
"superError": "Potrzebujesz uprawnienie Adminitsratora aby zakończyć tę akcję.",
|
||||
"terribleFailure": "Okropny błąd!"
|
||||
},
|
||||
"footer": {
|
||||
@ -201,25 +229,38 @@
|
||||
"preparingLogs": " Poczekaj kiedy my przygotowujemy twoje logi ... Wyślemy ci powiadomienie kiedy będą gotowe. To trochę zajmie na dużych serwerach.",
|
||||
"supportLogs": "Logi Pomocnicze"
|
||||
},
|
||||
"offline": {
|
||||
"offline": "Offline",
|
||||
"pleaseConnect": "Proszę połącz się z internetem aby korzystać z Craftiego."
|
||||
},
|
||||
"panelConfig": {
|
||||
"adminControls": "Ustawienia Admina",
|
||||
"allowedServers": "Zezwolone serwery",
|
||||
"apply": "Akceptuj",
|
||||
"assignedRoles": "Przypisane role",
|
||||
"cancel": "Anuluj",
|
||||
"clearComms": "Wyczyść nie wykonane komendy",
|
||||
"custom": "Dostosuj Craftiego",
|
||||
"delete": "Usuń",
|
||||
"edit": "Edytuj",
|
||||
"enabled": "Wlączone",
|
||||
"enableLang": "Włącz wszystkie języki",
|
||||
"globalExplain": "Gdzie Crafty trzyma wszystkie twoje serwery. (dołączymy /servers/[uuid of server] do ścieżki)",
|
||||
"globalServer": "Globalna ścieżka serwerów",
|
||||
"json": "Config.json",
|
||||
"match": "Hasła muszą być takie same",
|
||||
"newRole": "Dodaj nową role",
|
||||
"newUser": "Dodaj nowego użytkownika",
|
||||
"noMounts": "Nie pokazuj dysków w panelu",
|
||||
"pageTitle": "Ustawienia Panelu",
|
||||
"role": "Role",
|
||||
"roles": "Roles",
|
||||
"roleUsers": "Role użytkownika",
|
||||
"save": "Zapisz",
|
||||
"select": "Wybierz",
|
||||
"superConfirm": "Zapisz jeśli chcesz aby ten użytkownik miał dostęp do WSZYSTKIEGO (wszyscy użytkownicy, konta, serwery, ustawienia panelu, itp.). Mogą oni nawet usunąć twoje prawa SuperUżytkownika.",
|
||||
"superConfirmTitle": "Włączyć SuperUżytkownika? Jesteś pewien?",
|
||||
"title": "Konfiguracja Craftiego",
|
||||
"user": "Użytkownik",
|
||||
"users": "użytkownicy"
|
||||
},
|
||||
@ -243,14 +284,17 @@
|
||||
"roleTitle": "Ustawienia roli",
|
||||
"roleUserName": "Nazwa użytkownika",
|
||||
"roleUsers": "Dostęp do ról: ",
|
||||
"selectManager": "Wybierz zarządce dla tej roli",
|
||||
"serverAccess": "Dostęp?",
|
||||
"serverName": "Nazwa serwera",
|
||||
"serversDesc": "Serwery które mają tą role mają dostęp"
|
||||
},
|
||||
"serverBackups": {
|
||||
"after": "Wykonaj tę komendę po backupie",
|
||||
"backupAtMidnight": "Auto-backup o północy?",
|
||||
"backupNow": "Backup Teraz!",
|
||||
"backupTask": "Backup został rozpoczęty.",
|
||||
"before": "Wykonaj tę komendę przed backupem",
|
||||
"cancel": "Anuluj",
|
||||
"clickExclude": "Kliknij aby zaznaczyć wyjątki",
|
||||
"compress": "Skompresuj backup",
|
||||
@ -290,6 +334,8 @@
|
||||
"deleteServerQuestionMessage": "Jesteś pewien że chcesz usunąć ten serwer? To jest nie odwracalne...",
|
||||
"exeUpdateURL": "URL pliku egzekucyjnego serwera",
|
||||
"exeUpdateURLDesc": "Bezpośredni link dla aktualizacji.",
|
||||
"ignoredExits": "Ignoruj kody błędu przy crashu",
|
||||
"ignoredExitsExplain": "Kody błędu Crafty powinien rozumieć jako `stop` (odzielone przecinkiem)",
|
||||
"javaNoChange": "Nie nadpisuj",
|
||||
"javaVersion": "Nadpisz wersję Javy",
|
||||
"javaVersionDesc": "Jeśli chcesz nadpisać wersję javy. Upewnij się że twoja wersja javy w 'komendzie egzekucyjnej' jest zawinięta w cytaty (podstatowa zmienna 'java' jest wykluczona )",
|
||||
@ -320,7 +366,13 @@
|
||||
"serverPortDesc": "Port na jakim Crafty ma szukać statystyk",
|
||||
"serverStopCommand": "Komenda wyłączenia serwera",
|
||||
"serverStopCommandDesc": "Komenda, którą wyśle crafty aby wyłączyć serwer",
|
||||
"showStatus": "Pokazuj na publicznej stronie statusu",
|
||||
"shutdownTimeout": "Czas oczekiwania na zamknięcie",
|
||||
"statsHint1": "Port na którym operuje serwer. W ten sposób Crafty ma statystyki.",
|
||||
"statsHint2": "To nie zmienia portu serwera. Wciąż musisz go manualnie zmienić w server.properties.",
|
||||
"stopBeforeDeleting": "Zatrzymaj serwer przed jego usunięciem",
|
||||
"timeoutExplain1": "Jak długo musi Crafty czekać po `wyłączeniu` serwera",
|
||||
"timeoutExplain2": "aby wymusić zamknięcie.",
|
||||
"update": "Aktualizuj plik serwera",
|
||||
"yesDelete": "Tak, usuń",
|
||||
"yesDeleteFiles": "Tak, usuń pliki"
|
||||
@ -346,8 +398,12 @@
|
||||
"backup": "Backup",
|
||||
"config": "Konfiguracja",
|
||||
"files": "Pliki",
|
||||
"filter": "Filtruj Logi",
|
||||
"filterList": "Filtrowane słowa",
|
||||
"logs": "Logi",
|
||||
"metrics": "Statystyki",
|
||||
"playerControls": "Player Management",
|
||||
"reset": "Resetuj Scrolla",
|
||||
"schedule": "Harmonogram",
|
||||
"serverDetails": "Detale serwera",
|
||||
"terminal": "Konsola"
|
||||
@ -384,6 +440,11 @@
|
||||
"waitUpload": "Poczekaj, aż wyślemy twoje pliki... To może chwilkę zająć.",
|
||||
"yesDelete": "Tak, zdaję sobie sprawę z konsekfencji"
|
||||
},
|
||||
"serverMetrics": {
|
||||
"resetZoom": "Zresetuj Przybliżenie",
|
||||
"zoomHint1": "Aby Przybliżyć statystyki przytrzymaj shifta i użyj kółka na myszy.",
|
||||
"zoomHint2": "Albo przytrzymaj shifta i zaznacz strefę którą chcesz przybliżyć."
|
||||
},
|
||||
"serverPlayerManagement": {
|
||||
"bannedPlayers": "Zbanowani gracze",
|
||||
"loadingBannedPlayers": "Wczytuję zbanowanych graczy",
|
||||
@ -411,18 +472,36 @@
|
||||
"parent-explain": "Który harmonogram powinien wykonywać ten?",
|
||||
"reaction": "Reakcja",
|
||||
"restart": "Restart Serwera",
|
||||
"select": "Basic / Cron / Chain Zaznaczenie reakcji",
|
||||
"start": "Start Serwera",
|
||||
"stop": "Wyłącz Serwer",
|
||||
"time": "Czas",
|
||||
"time-explain": "O jakim czasie ma wykonać się ten harmonogram?"
|
||||
},
|
||||
"serverSchedules": {
|
||||
"action": "Akcja",
|
||||
"areYouSure": "Usuń zaplanowane (zadanie)?",
|
||||
"cancel": "Anuluj",
|
||||
"cannotSee": "Nie widzisz wszystkiego?",
|
||||
"cannotSeeOnMobile": "Spróbój kliknąć na zadanie dla detali.",
|
||||
"child": "ID dziecka harmonogramu ",
|
||||
"close": "Zamknij",
|
||||
"command": "Komenda",
|
||||
"confirm": "Zapisz",
|
||||
"confirmDelete": "Czy chcesz usunąć ten zaplanowany task? Jest to nieodwracalne."
|
||||
"confirmDelete": "Czy chcesz usunąć ten zaplanowany task? Jest to nieodwracalne.",
|
||||
"create": "Utwórz nowy harmonogram",
|
||||
"cron": "Crong String",
|
||||
"delete": "Usuń",
|
||||
"details": "Detale harmonogramu",
|
||||
"edit": "Edytuj",
|
||||
"enabled": "Włączony",
|
||||
"every": "Co",
|
||||
"interval": "Regularność",
|
||||
"name": "Nazwa",
|
||||
"nextRun": "Następne uruchomienie",
|
||||
"no": "Nie",
|
||||
"scheduledTasks": "Zaplanowane zadania",
|
||||
"yes": "Tak"
|
||||
},
|
||||
"serverStats": {
|
||||
"cpuUsage": "Użycie procesora",
|
||||
@ -444,7 +523,8 @@
|
||||
"serverTerm": {
|
||||
"commandInput": "Wpisz swoją komendę",
|
||||
"delay-explained": "Crafty niedawno się odpalił, właczanie serwera będzie trochę opóźnione",
|
||||
"downloading": "Pobieranie...",
|
||||
"importing": "Importowanie...",
|
||||
"installing": "Instalowanie...",
|
||||
"restart": "Restart",
|
||||
"sendCommand": "Wyślij komendę",
|
||||
"start": "Start",
|
||||
@ -469,6 +549,7 @@
|
||||
"importServer": "Importuj egzystujący serwer",
|
||||
"importServerButton": "Importuj serwer!",
|
||||
"importZip": "Importuj z ZIPa",
|
||||
"labelZipFile": "Wybierz swój plik ZIP",
|
||||
"maxMem": "Maks. RAMu",
|
||||
"minMem": "Min. RAMu",
|
||||
"myNewServer": "Mój nowy serwer",
|
||||
@ -478,7 +559,8 @@
|
||||
"resetForm": "Resetuj formę",
|
||||
"save": "Zapisz",
|
||||
"selectRole": "Zaznacz rolę (lub kilka)",
|
||||
"selectRoot": "Wybierz archiwum głównej ścieżki | (TBF, Select Archive Root Dir)",
|
||||
"selectRoot": "Wybierz główny katalog archiwa",
|
||||
"selectServer": "Wybierz Serwer",
|
||||
"selectType": "Wybierz typ serwera",
|
||||
"selectVersion": "Wybiesz wersje",
|
||||
"selectZipDir": "Wybierz ścieżkę w archiwóm którą chcesz abyśmy wypakowali",
|
||||
@ -486,9 +568,13 @@
|
||||
"serverName": "Nazwa serwera",
|
||||
"serverPath": "Ścieżka serwera",
|
||||
"serverPort": "Port serwera",
|
||||
"serverSelect": "Wybierz Serwer",
|
||||
"serverType": "Typ serwera",
|
||||
"serverVersion": "Wersja serwera",
|
||||
"serverUpload": "Wgraj ZIP Serwera",
|
||||
"sizeInGB": "Wielkość w GB",
|
||||
"uploadButton": "Wgraj",
|
||||
"uploadZip": "Wgraj plik Zip dla imprtowania serwera",
|
||||
"zipPath": "Server Path"
|
||||
},
|
||||
"sidebar": {
|
||||
@ -496,6 +582,7 @@
|
||||
"credits": "Podziękowania",
|
||||
"dashboard": "Panel",
|
||||
"documentation": "Dokumentacja",
|
||||
"inApp": "Dokumentacja w Aplikacji",
|
||||
"navigation": "Nawigacja",
|
||||
"newServer": "Stwórz nowy serwer",
|
||||
"servers": "Serwery"
|
||||
@ -520,6 +607,7 @@
|
||||
"lastLogin": "Ostatni login: ",
|
||||
"lastUpdate": "Ostatni update: ",
|
||||
"leaveBlank": "Jeśli chcesz zmienić użytkownika bez zmieniania hasła, nic nie wpisuj.",
|
||||
"manager": "Zarządca",
|
||||
"member": "Użytkownik?",
|
||||
"notExist": "Nie możesz usunąć czegoś, co nie istnieje!",
|
||||
"pageTitle": "Edytuj użytkownika",
|
||||
@ -528,6 +616,7 @@
|
||||
"permName": "Nazwa permisji",
|
||||
"repeat": "Powtórz hasło",
|
||||
"roleName": "Nazwa roli",
|
||||
"selectManager": "Wybierz zarządce dla tej roli",
|
||||
"super": "SuperUżytkownik",
|
||||
"userLang": "Język użytkownika",
|
||||
"userName": "Nazwa użytkownika",
|
||||
@ -535,6 +624,7 @@
|
||||
"userRoles": "Role użytkownika",
|
||||
"userRolesDesc": "Role, które ten użytkownik posiada.",
|
||||
"userSettings": "Ustawienia użytkownika",
|
||||
"userTheme": "Wygląd UI",
|
||||
"uses": "Ilość użyć (-1==Bez limitu)"
|
||||
}
|
||||
}
|
11
main.py
11
main.py
@ -27,6 +27,17 @@ if helper.check_root():
|
||||
time.sleep(5)
|
||||
Console.critical("Crafty shutting down. Root/Admin access denied.")
|
||||
sys.exit(0)
|
||||
if not (sys.version_info.major == 3 and sys.version_info.minor >= 9):
|
||||
Console.critical(
|
||||
"Python version mismatch. Python "
|
||||
f"{sys.version_info.major}.{sys.version_info.minor} detected."
|
||||
)
|
||||
Console.critical("Crafty requires Python 3.9 or above. Please upgrade python.")
|
||||
time.sleep(5)
|
||||
Console.critical("Crafty shutting down.")
|
||||
time.sleep(3)
|
||||
Console.info("Crafty stopped. Exiting...")
|
||||
sys.exit(0)
|
||||
# pylint: disable=wrong-import-position
|
||||
try:
|
||||
from app.classes.models.base_model import database_proxy
|
||||
|
@ -5,17 +5,17 @@ bleach==4.1
|
||||
cached_property==1.5.2
|
||||
colorama==0.4
|
||||
croniter==1.3.5
|
||||
cryptography==39.0.1
|
||||
cryptography==41.0.1
|
||||
libgravatar==1.0.0
|
||||
peewee==3.13
|
||||
pexpect==4.8
|
||||
psutil==5.9
|
||||
pyOpenSSL==23.0.0
|
||||
pyOpenSSL==23.2.0
|
||||
pyjwt==2.4.0
|
||||
PyYAML==5.4
|
||||
requests==2.26
|
||||
PyYAML==6.0.1
|
||||
requests==2.31
|
||||
termcolor==1.1
|
||||
tornado==6.0
|
||||
tornado==6.3.2
|
||||
tzlocal==4.0
|
||||
jsonschema==4.5.1
|
||||
orjson==3.6.7
|
||||
orjson==3.8.12
|
||||
|
14
sonar-project.properties
Normal file
14
sonar-project.properties
Normal file
@ -0,0 +1,14 @@
|
||||
sonar.projectKey=crafty-controller_crafty-4
|
||||
sonar.organization=crafty-controller
|
||||
|
||||
# This is the name and version displayed in the SonarCloud UI.
|
||||
sonar.projectName=Crafty 4
|
||||
sonar.projectVersion=4.1.4
|
||||
sonar.python.version=3.9, 3.10, 3.11
|
||||
sonar.exclusions=app/migrations/**, app/frontend/static/assets/vendors/**
|
||||
|
||||
# Path is relative to the sonar-project.properties file. Replace "\" by "/" on Windows.
|
||||
#sonar.sources=.
|
||||
|
||||
# Encoding of the source code. Default is default system encoding
|
||||
#sonar.sourceEncoding=UTF-8
|
Loading…
Reference in New Issue
Block a user