mirror of
https://gitlab.com/crafty-controller/crafty-4.git
synced 2024-08-30 18:23:09 +00:00
Merge branch 'dev' into dev-BetterDisplayMobile
This commit is contained in:
commit
bef099a5a8
@ -6,6 +6,7 @@ docker-compose.yml
|
||||
|
||||
# git & gitlab related
|
||||
.git/
|
||||
.gitlab/
|
||||
.gitignore
|
||||
.gitlab-ci.yml
|
||||
|
||||
|
@ -220,7 +220,7 @@ win-dev-build:
|
||||
--collect-all six
|
||||
|
||||
# Download latest:
|
||||
# | https://gitlab.com/crafty-controller/crafty-commander/-/jobs/artifacts/dev/download?job=win-dev-build
|
||||
# | https://gitlab.com/crafty-controller/crafty-4/-/jobs/artifacts/dev/download?job=win-dev-build
|
||||
artifacts:
|
||||
name: "crafty-${CI_RUNNER_TAGS}-${CI_COMMIT_BRANCH}_${CI_COMMIT_SHORT_SHA}"
|
||||
paths:
|
||||
@ -261,7 +261,7 @@ win-prod-build:
|
||||
--collect-all six
|
||||
|
||||
# Download latest:
|
||||
# | https://gitlab.com/crafty-controller/crafty-commander/-/jobs/artifacts/master/download?job=win-prod-build
|
||||
# | https://gitlab.com/crafty-controller/crafty-4/-/jobs/artifacts/master/download?job=win-prod-build
|
||||
artifacts:
|
||||
name: "crafty-${CI_RUNNER_TAGS}-${CI_COMMIT_BRANCH}_${CI_COMMIT_SHORT_SHA}"
|
||||
paths:
|
||||
|
15
.pylintrc
15
.pylintrc
@ -94,7 +94,6 @@ disable=C0330,
|
||||
fixme,
|
||||
import-error,
|
||||
inconsistent-return-statements,
|
||||
invalid-name,
|
||||
locally-disabled,
|
||||
logging-format-interpolation,
|
||||
logging-fstring-interpolation,
|
||||
@ -236,10 +235,20 @@ function-naming-style=snake_case
|
||||
#function-rgx=
|
||||
|
||||
# Good variable names which should always be accepted, separated by a comma.
|
||||
good-names=i,
|
||||
good-names=e,
|
||||
ex,
|
||||
f,
|
||||
i,
|
||||
id,
|
||||
ip,
|
||||
j,
|
||||
k,
|
||||
ex,
|
||||
p,
|
||||
r,
|
||||
rs,
|
||||
s,
|
||||
tz,
|
||||
v,
|
||||
Run,
|
||||
_
|
||||
|
||||
|
14
Dockerfile
14
Dockerfile
@ -7,8 +7,8 @@ ENV LOG4J_FORMAT_MSG_NO_LOOKUPS=true
|
||||
|
||||
# Create non-root user & required dirs
|
||||
RUN useradd -g root -M crafty \
|
||||
&& mkdir /commander \
|
||||
&& chown -R crafty:root /commander
|
||||
&& mkdir /crafty \
|
||||
&& chown -R crafty:root /crafty
|
||||
|
||||
# Install required system packages
|
||||
RUN apt-get update \
|
||||
@ -30,7 +30,7 @@ RUN apt-get update \
|
||||
|
||||
# Switch to service user for installing crafty deps
|
||||
USER crafty
|
||||
WORKDIR /commander
|
||||
WORKDIR /crafty
|
||||
COPY --chown=crafty:root requirements.txt ./
|
||||
RUN python3 -m venv ./.venv \
|
||||
&& . .venv/bin/activate \
|
||||
@ -51,8 +51,8 @@ EXPOSE 8443
|
||||
EXPOSE 19132
|
||||
EXPOSE 25500-25600
|
||||
|
||||
# Start Crafty Commander through wrapper
|
||||
ENTRYPOINT ["/commander/docker_launcher.sh"]
|
||||
# Start Crafty through wrapper
|
||||
ENTRYPOINT ["/crafty/docker_launcher.sh"]
|
||||
CMD ["-v", "-d", "-i"]
|
||||
|
||||
# Add meta labels
|
||||
@ -68,6 +68,6 @@ LABEL \
|
||||
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.source="https://gitlab.com/crafty-controller/crafty-commander" \
|
||||
org.opencontainers.image.source="https://gitlab.com/crafty-controller/crafty-4" \
|
||||
org.opencontainers.image.vendor="Arcadia Technology, LLC." \
|
||||
org.opencontainers.image.licenses=""
|
||||
org.opencontainers.image.licenses="GPL-3.0"
|
||||
|
86
README.md
86
README.md
@ -2,11 +2,11 @@
|
||||
|
||||
[](https://github.com/psf/black)
|
||||
[](https://www.python.org)
|
||||
[](https://gitlab.com/crafty-controller/crafty-commander)
|
||||
[](https://gitlab.com/crafty-controller/crafty-commander)
|
||||
[](https://gitlab.com/crafty-controller/crafty-commander/-/commits/master)
|
||||
[](https://gitlab.com/crafty-controller/crafty-4)
|
||||
[](https://gitlab.com/crafty-controller/crafty-4)
|
||||
[](https://gitlab.com/crafty-controller/crafty-4/-/commits/master)
|
||||
|
||||
# Crafty Controller 4.0.0-alpha.3.5
|
||||
# Crafty Controller 4.0.0-beta
|
||||
> Python based Control Panel for your Minecraft Server
|
||||
|
||||
## What is Crafty Controller?
|
||||
@ -23,7 +23,7 @@ Project Homepage - https://craftycontrol.com
|
||||
|
||||
Discord Server - https://discord.gg/9VJPhCE
|
||||
|
||||
Git Repository - https://gitlab.com/crafty-controller/crafty-web
|
||||
Git Repository - https://gitlab.com/crafty-controller/crafty-4
|
||||
|
||||
<br>
|
||||
|
||||
@ -39,7 +39,7 @@ With `Crafty Controller 4.0` we have focused on building our DevOps Principles,
|
||||
> __**⚠ 🔻WARNING: [WSL/WSL2 | WINDOWS 11 | DOCKER DESKTOP]🔻**__ <br>
|
||||
BE ADVISED! Upstream is currently broken for Minecraft running on **Docker under WSL/WSL2, Windows 11 / DOCKER DESKTOP!** <br>
|
||||
On '**Stop**' or '**Restart**' of the MC Server, there is a 90% chance the World's Chunks will be shredded irreparably! <br>
|
||||
Please only run Docker on Linux, If you are using Windows we have a portable installs found here: [Latest-Stable](https://gitlab.com/crafty-controller/crafty-commander/-/jobs/artifacts/master/download?job=win-prod-build), [Latest-Development](https://gitlab.com/crafty-controller/crafty-commander/-/jobs/artifacts/dev/download?job=win-dev-build)
|
||||
Please only run Docker on Linux, If you are using Windows we have a portable installs found here: [Latest-Stable](https://gitlab.com/crafty-controller/crafty-4/-/jobs/artifacts/master/download?job=win-prod-build), [Latest-Development](https://gitlab.com/crafty-controller/crafty-4/-/jobs/artifacts/dev/download?job=win-dev-build)
|
||||
|
||||
----
|
||||
|
||||
@ -55,35 +55,16 @@ As the Dockerfile uses the permission structure of `crafty:root` **internally**
|
||||
### - Using the registry image 🌎
|
||||
The provided image supports both `arm64` and `amd64` out the box, if you have issues though you can build it yourself with the `compose` file in `docker/`.
|
||||
|
||||
The image is located at: `registry.gitlab.com/crafty-controller/crafty-commander:latest`
|
||||
The image is located at: `registry.gitlab.com/crafty-controller/crafty-4:latest`
|
||||
| Branch | Status |
|
||||
| ----------------- | ------------------------------------------------------------------ |
|
||||
| :latest | [](https://gitlab.com/crafty-controller/crafty-commander/-/commits/master) |
|
||||
| :dev | [](https://gitlab.com/crafty-controller/crafty-commander/-/commits/dev) |
|
||||
| :latest | [](https://gitlab.com/crafty-controller/crafty-4/-/commits/master) |
|
||||
| :dev | [](https://gitlab.com/crafty-controller/crafty-4/-/commits/dev)
|
||||
|
||||
While the repository is still **private / pre-release**,
|
||||
Before you can pull the image you must authenticate docker with the Container Registry.
|
||||
<br>
|
||||
|
||||
To authenticate you will need a [personal access token](https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html)
|
||||
with the minimum scope:
|
||||
**Here are some example methods for getting started🚀:**
|
||||
|
||||
- For read (*pull*) access, `read_registry`.
|
||||
- For write (*push*) access, `write_registry`.
|
||||
|
||||
When you have this just run:
|
||||
```bash
|
||||
$ docker login registry.gitlab.com -u <username> -p <token>
|
||||
```
|
||||
or
|
||||
```bash
|
||||
$ echo <token> | docker login registry.gitlab.com -u <username> --password-stdin
|
||||
```
|
||||
or
|
||||
```bash
|
||||
$ cat ~/my_password.txt | docker login registry.gitlab.com -u <username> --password-stdin
|
||||
```
|
||||
|
||||
Then use one of the following methods:
|
||||
### **docker-compose.yml:**
|
||||
```sh
|
||||
# Make your compose file
|
||||
@ -94,8 +75,9 @@ version: '3'
|
||||
|
||||
services:
|
||||
crafty:
|
||||
container_name: crafty_commander
|
||||
image: registry.gitlab.com/crafty-controller/crafty-commander:latest
|
||||
container_name: crafty_container
|
||||
image: registry.gitlab.com/crafty-controller/crafty-4:latest
|
||||
restart: always
|
||||
environment:
|
||||
- TZ=Etc/UTC
|
||||
ports:
|
||||
@ -105,11 +87,11 @@ services:
|
||||
- "19132:19132/udp" # BEDROCK
|
||||
- "25500-25600:25500-25600" # MC SERV PORT RANGE
|
||||
volumes:
|
||||
- ./docker/backups:/commander/backups
|
||||
- ./docker/logs:/commander/logs
|
||||
- ./docker/servers:/commander/servers
|
||||
- ./docker/config:/commander/app/config
|
||||
- ./docker/import:/commander/import
|
||||
- ./docker/backups:/crafty/backups
|
||||
- ./docker/logs:/crafty/logs
|
||||
- ./docker/servers:/crafty/servers
|
||||
- ./docker/config:/crafty/app/config
|
||||
- ./docker/import:/crafty/import
|
||||
```
|
||||
```sh
|
||||
$ docker-compose up -d && docker-compose logs -f
|
||||
@ -119,19 +101,21 @@ $ docker-compose up -d && docker-compose logs -f
|
||||
### **docker run:**
|
||||
```sh
|
||||
$ docker run \
|
||||
--name crafty_commander \
|
||||
--name crafty_container \
|
||||
--detach \
|
||||
--restart always \
|
||||
-p 8000:8000 \
|
||||
-p 8443:8443 \
|
||||
-p 8123:8123 \
|
||||
-p 19132:19132/udp \
|
||||
-p 25500-25600:25500-25600 \
|
||||
-e TZ=Etc/UTC \
|
||||
-v "/$(pwd)/docker/backups:/commander/backups" \
|
||||
-v "/$(pwd)/docker/logs:/commander/logs" \
|
||||
-v "/$(pwd)/docker/servers:/commander/servers" \
|
||||
-v "/$(pwd)/docker/config:/commander/app/config" \
|
||||
-v "/$(pwd)/docker/import:/commander/import" \
|
||||
registry.gitlab.com/crafty-controller/crafty-commander:latest
|
||||
-v "/$(pwd)/docker/backups:/crafty/backups" \
|
||||
-v "/$(pwd)/docker/logs:/crafty/logs" \
|
||||
-v "/$(pwd)/docker/servers:/crafty/servers" \
|
||||
-v "/$(pwd)/docker/config:/crafty/app/config" \
|
||||
-v "/$(pwd)/docker/import:/crafty/import" \
|
||||
registry.gitlab.com/crafty-controller/crafty-4:latest
|
||||
```
|
||||
|
||||
### **Building from the cloned repository:**
|
||||
@ -144,18 +128,20 @@ If you'd rather not use `docker-compose` you can use the following `docker run`
|
||||
$ docker build . -t crafty
|
||||
|
||||
$ docker run \
|
||||
--name crafty_commander \
|
||||
--name crafty_container \
|
||||
--detach \
|
||||
--restart always \
|
||||
-p 8000:8000 \
|
||||
-p 8443:8443 \
|
||||
-p 8123:8123 \
|
||||
-p 19132:19132/udp \
|
||||
-p 25500-25600:25500-25600 \
|
||||
-e TZ=Etc/UTC \
|
||||
-v "/$(pwd)/docker/backups:/commander/backups" \
|
||||
-v "/$(pwd)/docker/logs:/commander/logs" \
|
||||
-v "/$(pwd)/docker/servers:/commander/servers" \
|
||||
-v "/$(pwd)/docker/config:/commander/app/config" \
|
||||
-v "/$(pwd)/docker/import:/commander/import" \
|
||||
-v "/$(pwd)/docker/backups:/crafty/backups" \
|
||||
-v "/$(pwd)/docker/logs:/crafty/logs" \
|
||||
-v "/$(pwd)/docker/servers:/crafty/servers" \
|
||||
-v "/$(pwd)/docker/config:/crafty/app/config" \
|
||||
-v "/$(pwd)/docker/import:/crafty/import" \
|
||||
crafty
|
||||
```
|
||||
A fresh build will take several minutes depending on your system, but will be rapid thereafter.
|
||||
|
@ -1,37 +1,37 @@
|
||||
import logging
|
||||
|
||||
from app.classes.models.crafty_permissions import (
|
||||
crafty_permissions,
|
||||
Enum_Permissions_Crafty,
|
||||
PermissionsCrafty,
|
||||
EnumPermissionsCrafty,
|
||||
)
|
||||
from app.classes.models.users import ApiKeys
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Crafty_Perms_Controller:
|
||||
class CraftyPermsController:
|
||||
@staticmethod
|
||||
def list_defined_crafty_permissions():
|
||||
permissions_list = crafty_permissions.get_permissions_list()
|
||||
permissions_list = PermissionsCrafty.get_permissions_list()
|
||||
return permissions_list
|
||||
|
||||
@staticmethod
|
||||
def get_mask_crafty_permissions(user_id):
|
||||
permissions_mask = crafty_permissions.get_crafty_permissions_mask(user_id)
|
||||
permissions_mask = PermissionsCrafty.get_crafty_permissions_mask(user_id)
|
||||
return permissions_mask
|
||||
|
||||
@staticmethod
|
||||
def set_permission(
|
||||
permission_mask, permission_tested: Enum_Permissions_Crafty, value
|
||||
permission_mask, permission_tested: EnumPermissionsCrafty, value
|
||||
):
|
||||
return crafty_permissions.set_permission(
|
||||
return PermissionsCrafty.set_permission(
|
||||
permission_mask, permission_tested, value
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def can_create_server(user_id):
|
||||
return crafty_permissions.can_add_in_crafty(
|
||||
user_id, Enum_Permissions_Crafty.Server_Creation
|
||||
return PermissionsCrafty.can_add_in_crafty(
|
||||
user_id, EnumPermissionsCrafty.SERVER_CREATION
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
@ -52,22 +52,22 @@ class Crafty_Perms_Controller:
|
||||
|
||||
@staticmethod
|
||||
def list_all_crafty_permissions_quantity_limits():
|
||||
return crafty_permissions.get_all_permission_quantity_list()
|
||||
return PermissionsCrafty.get_all_permission_quantity_list()
|
||||
|
||||
@staticmethod
|
||||
def list_crafty_permissions_quantity_limits(user_id):
|
||||
return crafty_permissions.get_permission_quantity_list(user_id)
|
||||
return PermissionsCrafty.get_permission_quantity_list(user_id)
|
||||
|
||||
@staticmethod
|
||||
def get_crafty_permissions_list(user_id):
|
||||
permissions_mask = crafty_permissions.get_crafty_permissions_mask(user_id)
|
||||
permissions_list = crafty_permissions.get_permissions(permissions_mask)
|
||||
permissions_mask = PermissionsCrafty.get_crafty_permissions_mask(user_id)
|
||||
permissions_list = PermissionsCrafty.get_permissions(permissions_mask)
|
||||
return permissions_list
|
||||
|
||||
@staticmethod
|
||||
def add_server_creation(user_id):
|
||||
return crafty_permissions.add_server_creation(user_id)
|
||||
return PermissionsCrafty.add_server_creation(user_id)
|
||||
|
||||
@staticmethod
|
||||
def get_api_key_permissions_list(key: ApiKeys):
|
||||
return crafty_permissions.get_api_key_permissions_list(key)
|
||||
return PermissionsCrafty.get_api_key_permissions_list(key)
|
||||
|
@ -1,60 +1,59 @@
|
||||
import logging
|
||||
|
||||
from app.classes.models.management import management_helper
|
||||
from app.classes.models.servers import servers_helper
|
||||
from app.classes.models.management import HelpersManagement
|
||||
from app.classes.models.servers import HelperServers
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Management_Controller:
|
||||
class ManagementController:
|
||||
def __init__(self, management_helper):
|
||||
self.management_helper = management_helper
|
||||
|
||||
# **********************************************************************************
|
||||
# Host_Stats Methods
|
||||
# **********************************************************************************
|
||||
@staticmethod
|
||||
def get_latest_hosts_stats():
|
||||
return management_helper.get_latest_hosts_stats()
|
||||
return HelpersManagement.get_latest_hosts_stats()
|
||||
|
||||
# **********************************************************************************
|
||||
# Commands Methods
|
||||
# **********************************************************************************
|
||||
@staticmethod
|
||||
def get_unactioned_commands():
|
||||
return management_helper.get_unactioned_commands()
|
||||
return HelpersManagement.get_unactioned_commands()
|
||||
|
||||
@staticmethod
|
||||
def send_command(user_id, server_id, remote_ip, command):
|
||||
server_name = servers_helper.get_server_friendly_name(server_id)
|
||||
def send_command(self, user_id, server_id, remote_ip, command):
|
||||
server_name = HelperServers.get_server_friendly_name(server_id)
|
||||
|
||||
# Example: Admin issued command start_server for server Survival
|
||||
management_helper.add_to_audit_log(
|
||||
self.management_helper.add_to_audit_log(
|
||||
user_id,
|
||||
f"issued command {command} for server {server_name}",
|
||||
server_id,
|
||||
remote_ip,
|
||||
)
|
||||
management_helper.add_command(server_id, user_id, remote_ip, command)
|
||||
HelpersManagement.add_command(server_id, user_id, remote_ip, command)
|
||||
|
||||
@staticmethod
|
||||
def mark_command_complete(command_id=None):
|
||||
return management_helper.mark_command_complete(command_id)
|
||||
return HelpersManagement.mark_command_complete(command_id)
|
||||
|
||||
# **********************************************************************************
|
||||
# Audit_Log Methods
|
||||
# **********************************************************************************
|
||||
@staticmethod
|
||||
def get_actity_log():
|
||||
return management_helper.get_actity_log()
|
||||
return HelpersManagement.get_actity_log()
|
||||
|
||||
@staticmethod
|
||||
def add_to_audit_log(user_id, log_msg, server_id=None, source_ip=None):
|
||||
return management_helper.add_to_audit_log(
|
||||
def add_to_audit_log(self, user_id, log_msg, server_id=None, source_ip=None):
|
||||
return self.management_helper.add_to_audit_log(
|
||||
user_id, log_msg, server_id, source_ip
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def add_to_audit_log_raw(user_name, user_id, server_id, log_msg, source_ip):
|
||||
return management_helper.add_to_audit_log_raw(
|
||||
def add_to_audit_log_raw(self, user_name, user_id, server_id, log_msg, source_ip):
|
||||
return self.management_helper.add_to_audit_log_raw(
|
||||
user_name, user_id, server_id, log_msg, source_ip
|
||||
)
|
||||
|
||||
@ -72,7 +71,7 @@ class Management_Controller:
|
||||
comment=None,
|
||||
enabled=True,
|
||||
):
|
||||
return management_helper.create_scheduled_task(
|
||||
return HelpersManagement.create_scheduled_task(
|
||||
server_id,
|
||||
action,
|
||||
interval,
|
||||
@ -85,63 +84,61 @@ class Management_Controller:
|
||||
|
||||
@staticmethod
|
||||
def delete_scheduled_task(schedule_id):
|
||||
return management_helper.delete_scheduled_task(schedule_id)
|
||||
return HelpersManagement.delete_scheduled_task(schedule_id)
|
||||
|
||||
@staticmethod
|
||||
def update_scheduled_task(schedule_id, updates):
|
||||
return management_helper.update_scheduled_task(schedule_id, updates)
|
||||
return HelpersManagement.update_scheduled_task(schedule_id, updates)
|
||||
|
||||
@staticmethod
|
||||
def get_scheduled_task(schedule_id):
|
||||
return management_helper.get_scheduled_task(schedule_id)
|
||||
return HelpersManagement.get_scheduled_task(schedule_id)
|
||||
|
||||
@staticmethod
|
||||
def get_scheduled_task_model(schedule_id):
|
||||
return management_helper.get_scheduled_task_model(schedule_id)
|
||||
return HelpersManagement.get_scheduled_task_model(schedule_id)
|
||||
|
||||
@staticmethod
|
||||
def get_child_schedules(sch_id):
|
||||
return management_helper.get_child_schedules(sch_id)
|
||||
return HelpersManagement.get_child_schedules(sch_id)
|
||||
|
||||
@staticmethod
|
||||
def get_schedules_by_server(server_id):
|
||||
return management_helper.get_schedules_by_server(server_id)
|
||||
return HelpersManagement.get_schedules_by_server(server_id)
|
||||
|
||||
@staticmethod
|
||||
def get_schedules_all():
|
||||
return management_helper.get_schedules_all()
|
||||
return HelpersManagement.get_schedules_all()
|
||||
|
||||
@staticmethod
|
||||
def get_schedules_enabled():
|
||||
return management_helper.get_schedules_enabled()
|
||||
return HelpersManagement.get_schedules_enabled()
|
||||
|
||||
# **********************************************************************************
|
||||
# Backups Methods
|
||||
# **********************************************************************************
|
||||
@staticmethod
|
||||
def get_backup_config(server_id):
|
||||
return management_helper.get_backup_config(server_id)
|
||||
return HelpersManagement.get_backup_config(server_id)
|
||||
|
||||
@staticmethod
|
||||
def set_backup_config(
|
||||
self,
|
||||
server_id: int,
|
||||
backup_path: str = None,
|
||||
max_backups: int = None,
|
||||
excluded_dirs: list = None,
|
||||
compress: bool = False,
|
||||
):
|
||||
return management_helper.set_backup_config(
|
||||
return self.management_helper.set_backup_config(
|
||||
server_id, backup_path, max_backups, excluded_dirs, compress
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def get_excluded_backup_dirs(server_id: int):
|
||||
return management_helper.get_excluded_backup_dirs(server_id)
|
||||
return HelpersManagement.get_excluded_backup_dirs(server_id)
|
||||
|
||||
@staticmethod
|
||||
def add_excluded_backup_dir(server_id: int, dir_to_add: str):
|
||||
management_helper.add_excluded_backup_dir(server_id, dir_to_add)
|
||||
def add_excluded_backup_dir(self, server_id: int, dir_to_add: str):
|
||||
self.management_helper.add_excluded_backup_dir(server_id, dir_to_add)
|
||||
|
||||
@staticmethod
|
||||
def del_excluded_backup_dir(server_id: int, dir_to_del: str):
|
||||
management_helper.del_excluded_backup_dir(server_id, dir_to_del)
|
||||
def del_excluded_backup_dir(self, server_id: int, dir_to_del: str):
|
||||
self.management_helper.del_excluded_backup_dir(server_id, dir_to_del)
|
||||
|
@ -1,31 +1,34 @@
|
||||
import logging
|
||||
|
||||
from app.classes.models.roles import roles_helper
|
||||
from app.classes.models.server_permissions import server_permissions
|
||||
from app.classes.models.users import users_helper
|
||||
from app.classes.shared.helpers import helper
|
||||
from app.classes.models.roles import HelperRoles
|
||||
from app.classes.models.server_permissions import PermissionsServers
|
||||
from app.classes.shared.helpers import Helpers
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Roles_Controller:
|
||||
class RolesController:
|
||||
def __init__(self, users_helper, roles_helper):
|
||||
self.users_helper = users_helper
|
||||
self.roles_helper = roles_helper
|
||||
|
||||
@staticmethod
|
||||
def get_all_roles():
|
||||
return roles_helper.get_all_roles()
|
||||
return HelperRoles.get_all_roles()
|
||||
|
||||
@staticmethod
|
||||
def get_roleid_by_name(role_name):
|
||||
return roles_helper.get_roleid_by_name(role_name)
|
||||
return HelperRoles.get_roleid_by_name(role_name)
|
||||
|
||||
@staticmethod
|
||||
def get_role(role_id):
|
||||
return roles_helper.get_role(role_id)
|
||||
return HelperRoles.get_role(role_id)
|
||||
|
||||
@staticmethod
|
||||
def update_role(role_id: str, role_data=None, permissions_mask: str = "00000000"):
|
||||
if role_data is None:
|
||||
role_data = {}
|
||||
base_data = Roles_Controller.get_role_with_servers(role_id)
|
||||
base_data = RolesController.get_role_with_servers(role_id)
|
||||
up_data = {}
|
||||
added_servers = set()
|
||||
removed_servers = set()
|
||||
@ -37,41 +40,40 @@ class Roles_Controller:
|
||||
removed_servers = base_data["servers"].difference(role_data["servers"])
|
||||
elif base_data[key] != role_data[key]:
|
||||
up_data[key] = role_data[key]
|
||||
up_data["last_update"] = helper.get_time_as_string()
|
||||
up_data["last_update"] = Helpers.get_time_as_string()
|
||||
logger.debug(
|
||||
f"role: {role_data} +server:{added_servers} -server{removed_servers}"
|
||||
)
|
||||
for server in added_servers:
|
||||
server_permissions.get_or_create(role_id, server, permissions_mask)
|
||||
PermissionsServers.get_or_create(role_id, server, permissions_mask)
|
||||
for server in base_data["servers"]:
|
||||
server_permissions.update_role_permission(role_id, server, permissions_mask)
|
||||
PermissionsServers.update_role_permission(role_id, server, permissions_mask)
|
||||
# TODO: This is horribly inefficient and we should be using bulk queries
|
||||
# but im going for functionality at this point
|
||||
server_permissions.delete_roles_permissions(role_id, removed_servers)
|
||||
PermissionsServers.delete_roles_permissions(role_id, removed_servers)
|
||||
if up_data:
|
||||
roles_helper.update_role(role_id, up_data)
|
||||
HelperRoles.update_role(role_id, up_data)
|
||||
|
||||
@staticmethod
|
||||
def add_role(role_name):
|
||||
return roles_helper.add_role(role_name)
|
||||
return HelperRoles.add_role(role_name)
|
||||
|
||||
@staticmethod
|
||||
def remove_role(role_id):
|
||||
role_data = Roles_Controller.get_role_with_servers(role_id)
|
||||
server_permissions.delete_roles_permissions(role_id, role_data["servers"])
|
||||
users_helper.remove_roles_from_role_id(role_id)
|
||||
return roles_helper.remove_role(role_id)
|
||||
def remove_role(self, role_id):
|
||||
role_data = RolesController.get_role_with_servers(role_id)
|
||||
PermissionsServers.delete_roles_permissions(role_id, role_data["servers"])
|
||||
self.users_helper.remove_roles_from_role_id(role_id)
|
||||
return self.roles_helper.remove_role(role_id)
|
||||
|
||||
@staticmethod
|
||||
def role_id_exists(role_id):
|
||||
return roles_helper.role_id_exists(role_id)
|
||||
return HelperRoles.role_id_exists(role_id)
|
||||
|
||||
@staticmethod
|
||||
def get_role_with_servers(role_id):
|
||||
role = roles_helper.get_role(role_id)
|
||||
role = HelperRoles.get_role(role_id)
|
||||
|
||||
if role:
|
||||
servers_query = server_permissions.get_servers_from_role(role_id)
|
||||
servers_query = PermissionsServers.get_servers_from_role(role_id)
|
||||
# TODO: this query needs to be narrower
|
||||
servers = set()
|
||||
for s in servers_query:
|
||||
|
@ -1,114 +1,122 @@
|
||||
import logging
|
||||
|
||||
from app.classes.models.server_permissions import (
|
||||
server_permissions,
|
||||
Enum_Permissions_Server,
|
||||
PermissionsServers,
|
||||
EnumPermissionsServer,
|
||||
)
|
||||
from app.classes.models.users import users_helper, ApiKeys
|
||||
from app.classes.models.roles import roles_helper
|
||||
from app.classes.models.servers import servers_helper
|
||||
from app.classes.shared.main_models import db_helper
|
||||
from app.classes.models.users import HelperUsers, ApiKeys
|
||||
from app.classes.models.roles import HelperRoles
|
||||
from app.classes.models.servers import HelperServers
|
||||
from app.classes.models.server_stats import HelperServerStats
|
||||
from app.classes.shared.main_models import DatabaseShortcuts
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Server_Perms_Controller:
|
||||
class ServerPermsController:
|
||||
@staticmethod
|
||||
def get_server_user_list(server_id):
|
||||
return server_permissions.get_server_user_list(server_id)
|
||||
return PermissionsServers.get_server_user_list(server_id)
|
||||
|
||||
@staticmethod
|
||||
def list_defined_permissions():
|
||||
permissions_list = server_permissions.get_permissions_list()
|
||||
permissions_list = PermissionsServers.get_permissions_list()
|
||||
return permissions_list
|
||||
|
||||
@staticmethod
|
||||
def get_mask_permissions(role_id, server_id):
|
||||
permissions_mask = server_permissions.get_permissions_mask(role_id, server_id)
|
||||
permissions_mask = PermissionsServers.get_permissions_mask(role_id, server_id)
|
||||
return permissions_mask
|
||||
|
||||
@staticmethod
|
||||
def get_role_permissions(role_id):
|
||||
permissions_list = server_permissions.get_role_permissions_list(role_id)
|
||||
permissions_list = PermissionsServers.get_role_permissions_list(role_id)
|
||||
return permissions_list
|
||||
|
||||
@staticmethod
|
||||
def add_role_server(server_id, role_id, rs_permissions="00000000"):
|
||||
return server_permissions.add_role_server(server_id, role_id, rs_permissions)
|
||||
return PermissionsServers.add_role_server(server_id, role_id, rs_permissions)
|
||||
|
||||
@staticmethod
|
||||
def get_server_roles(server_id):
|
||||
return server_permissions.get_server_roles(server_id)
|
||||
return PermissionsServers.get_server_roles(server_id)
|
||||
|
||||
@staticmethod
|
||||
def backup_role_swap(old_server_id, new_server_id):
|
||||
role_list = server_permissions.get_server_roles(old_server_id)
|
||||
role_list = PermissionsServers.get_server_roles(old_server_id)
|
||||
for role in role_list:
|
||||
server_permissions.add_role_server(
|
||||
PermissionsServers.add_role_server(
|
||||
new_server_id,
|
||||
role.role_id,
|
||||
server_permissions.get_permissions_mask(
|
||||
PermissionsServers.get_permissions_mask(
|
||||
int(role.role_id), int(old_server_id)
|
||||
),
|
||||
)
|
||||
# server_permissions.add_role_server(new_server_id, role.role_id,"00001000")
|
||||
# Permissions_Servers.add_role_server(
|
||||
# new_server_id, role.role_id, "00001000"
|
||||
# )
|
||||
|
||||
# **********************************************************************************
|
||||
# Servers Permissions Methods
|
||||
# **********************************************************************************
|
||||
@staticmethod
|
||||
def get_permissions_mask(role_id, server_id):
|
||||
return server_permissions.get_permissions_mask(role_id, server_id)
|
||||
return PermissionsServers.get_permissions_mask(role_id, server_id)
|
||||
|
||||
@staticmethod
|
||||
def set_permission(
|
||||
permission_mask, permission_tested: Enum_Permissions_Server, value
|
||||
permission_mask, permission_tested: EnumPermissionsServer, value
|
||||
):
|
||||
return server_permissions.set_permission(
|
||||
return PermissionsServers.set_permission(
|
||||
permission_mask, permission_tested, value
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def get_role_permissions_list(role_id):
|
||||
return server_permissions.get_role_permissions_list(role_id)
|
||||
return PermissionsServers.get_role_permissions_list(role_id)
|
||||
|
||||
@staticmethod
|
||||
def get_user_id_permissions_list(user_id: str, server_id: str):
|
||||
return server_permissions.get_user_id_permissions_list(user_id, server_id)
|
||||
return PermissionsServers.get_user_id_permissions_list(user_id, server_id)
|
||||
|
||||
@staticmethod
|
||||
def get_api_key_id_permissions_list(key_id: str, server_id: str):
|
||||
key = users_helper.get_user_api_key(key_id)
|
||||
return server_permissions.get_api_key_permissions_list(key, server_id)
|
||||
key = HelperUsers.get_user_api_key(key_id)
|
||||
return PermissionsServers.get_api_key_permissions_list(key, server_id)
|
||||
|
||||
@staticmethod
|
||||
def get_api_key_permissions_list(key: ApiKeys, server_id: str):
|
||||
return server_permissions.get_api_key_permissions_list(key, server_id)
|
||||
return PermissionsServers.get_api_key_permissions_list(key, server_id)
|
||||
|
||||
@staticmethod
|
||||
def get_authorized_servers_stats_from_roles(user_id):
|
||||
user_roles = users_helper.get_user_roles_id(user_id)
|
||||
user_roles = HelperUsers.get_user_roles_id(user_id)
|
||||
roles_list = []
|
||||
role_server = []
|
||||
authorized_servers = []
|
||||
server_data = []
|
||||
|
||||
for u in user_roles:
|
||||
roles_list.append(roles_helper.get_role(u.role_id))
|
||||
for user in user_roles:
|
||||
roles_list.append(HelperRoles.get_role(user.role_id))
|
||||
|
||||
for r in roles_list:
|
||||
role_test = server_permissions.get_role_servers_from_role_id(
|
||||
r.get("role_id")
|
||||
for role in roles_list:
|
||||
role_test = PermissionsServers.get_role_servers_from_role_id(
|
||||
role.get("role_id")
|
||||
)
|
||||
for t in role_test:
|
||||
role_server.append(t)
|
||||
for test in role_test:
|
||||
role_server.append(test)
|
||||
|
||||
for s in role_server:
|
||||
authorized_servers.append(servers_helper.get_server_data_by_id(s.server_id))
|
||||
for server in role_server:
|
||||
authorized_servers.append(
|
||||
HelperServers.get_server_data_by_id(server.server_id)
|
||||
)
|
||||
|
||||
for s in authorized_servers:
|
||||
latest = servers_helper.get_latest_server_stats(s.get("server_id"))
|
||||
for server in authorized_servers:
|
||||
latest = HelperServerStats.get_latest_server_stats(server.get("server_id"))
|
||||
server_data.append(
|
||||
{"server_data": s, "stats": db_helper.return_rows(latest)[0]}
|
||||
{
|
||||
"server_data": server,
|
||||
"stats": DatabaseShortcuts.return_rows(latest)[0],
|
||||
}
|
||||
)
|
||||
return server_data
|
||||
|
@ -2,26 +2,29 @@ import os
|
||||
import logging
|
||||
import json
|
||||
|
||||
from app.classes.controllers.roles_controller import Roles_Controller
|
||||
from app.classes.models.servers import servers_helper
|
||||
from app.classes.models.users import users_helper, ApiKeys
|
||||
from app.classes.controllers.roles_controller import RolesController
|
||||
from app.classes.models.servers import HelperServers
|
||||
from app.classes.models.server_stats import HelperServerStats
|
||||
from app.classes.models.users import HelperUsers, ApiKeys
|
||||
from app.classes.models.server_permissions import (
|
||||
server_permissions,
|
||||
Enum_Permissions_Server,
|
||||
PermissionsServers,
|
||||
EnumPermissionsServer,
|
||||
)
|
||||
from app.classes.shared.helpers import helper
|
||||
from app.classes.shared.main_models import db_helper
|
||||
from app.classes.shared.helpers import Helpers
|
||||
from app.classes.shared.main_models import DatabaseShortcuts
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Servers_Controller:
|
||||
class ServersController:
|
||||
def __init__(self, servers_helper):
|
||||
self.servers_helper = servers_helper
|
||||
|
||||
# **********************************************************************************
|
||||
# Generic Servers Methods
|
||||
# **********************************************************************************
|
||||
@staticmethod
|
||||
def create_server(
|
||||
self,
|
||||
name: str,
|
||||
server_uuid: str,
|
||||
server_dir: str,
|
||||
@ -33,7 +36,7 @@ class Servers_Controller:
|
||||
server_type: str,
|
||||
server_port=25565,
|
||||
):
|
||||
return servers_helper.create_server(
|
||||
return self.servers_helper.create_server(
|
||||
name,
|
||||
server_uuid,
|
||||
server_dir,
|
||||
@ -48,81 +51,82 @@ class Servers_Controller:
|
||||
|
||||
@staticmethod
|
||||
def get_server_obj(server_id):
|
||||
return servers_helper.get_server_obj(server_id)
|
||||
return HelperServers.get_server_obj(server_id)
|
||||
|
||||
@staticmethod
|
||||
def update_server(server_obj):
|
||||
return servers_helper.update_server(server_obj)
|
||||
return HelperServers.update_server(server_obj)
|
||||
|
||||
@staticmethod
|
||||
def set_download(server_id):
|
||||
return servers_helper.set_download(server_id)
|
||||
return HelperServerStats.set_download(server_id)
|
||||
|
||||
@staticmethod
|
||||
def finish_download(server_id):
|
||||
return servers_helper.finish_download(server_id)
|
||||
return HelperServerStats.finish_download(server_id)
|
||||
|
||||
@staticmethod
|
||||
def get_download_status(server_id):
|
||||
return servers_helper.get_download_status(server_id)
|
||||
return HelperServerStats.get_download_status(server_id)
|
||||
|
||||
@staticmethod
|
||||
def remove_server(server_id):
|
||||
roles_list = server_permissions.get_roles_from_server(server_id)
|
||||
def remove_server(self, server_id):
|
||||
roles_list = PermissionsServers.get_roles_from_server(server_id)
|
||||
for role in roles_list:
|
||||
role_id = role.role_id
|
||||
role_data = Roles_Controller.get_role_with_servers(role_id)
|
||||
role_data = RolesController.get_role_with_servers(role_id)
|
||||
role_data["servers"] = {server_id}
|
||||
server_permissions.delete_roles_permissions(role_id, role_data["servers"])
|
||||
server_permissions.remove_roles_of_server(server_id)
|
||||
servers_helper.remove_server(server_id)
|
||||
PermissionsServers.delete_roles_permissions(role_id, role_data["servers"])
|
||||
PermissionsServers.remove_roles_of_server(server_id)
|
||||
self.servers_helper.remove_server(server_id)
|
||||
|
||||
@staticmethod
|
||||
def get_server_data_by_id(server_id):
|
||||
return servers_helper.get_server_data_by_id(server_id)
|
||||
return HelperServers.get_server_data_by_id(server_id)
|
||||
|
||||
# **********************************************************************************
|
||||
# Servers Methods
|
||||
# **********************************************************************************
|
||||
@staticmethod
|
||||
def get_all_defined_servers():
|
||||
return servers_helper.get_all_defined_servers()
|
||||
return HelperServers.get_all_defined_servers()
|
||||
|
||||
@staticmethod
|
||||
def get_authorized_servers(user_id):
|
||||
server_data = []
|
||||
user_roles = users_helper.user_role_query(user_id)
|
||||
for us in user_roles:
|
||||
role_servers = server_permissions.get_role_servers_from_role_id(us.role_id)
|
||||
user_roles = HelperUsers.user_role_query(user_id)
|
||||
for user in user_roles:
|
||||
role_servers = PermissionsServers.get_role_servers_from_role_id(
|
||||
user.role_id
|
||||
)
|
||||
for role in role_servers:
|
||||
server_data.append(servers_helper.get_server_data_by_id(role.server_id))
|
||||
server_data.append(HelperServers.get_server_data_by_id(role.server_id))
|
||||
|
||||
return server_data
|
||||
|
||||
@staticmethod
|
||||
def get_all_servers_stats():
|
||||
return servers_helper.get_all_servers_stats()
|
||||
return HelperServerStats.get_all_servers_stats()
|
||||
|
||||
@staticmethod
|
||||
def get_authorized_servers_stats_api_key(api_key: ApiKeys):
|
||||
server_data = []
|
||||
authorized_servers = Servers_Controller.get_authorized_servers(
|
||||
authorized_servers = ServersController.get_authorized_servers(
|
||||
api_key.user.user_id
|
||||
)
|
||||
|
||||
for s in authorized_servers:
|
||||
latest = servers_helper.get_latest_server_stats(s.get("server_id"))
|
||||
key_permissions = server_permissions.get_api_key_permissions_list(
|
||||
api_key, s.get("server_id")
|
||||
for server in authorized_servers:
|
||||
latest = HelperServerStats.get_latest_server_stats(server.get("server_id"))
|
||||
key_permissions = PermissionsServers.get_api_key_permissions_list(
|
||||
api_key, server.get("server_id")
|
||||
)
|
||||
if Enum_Permissions_Server.Commands in key_permissions:
|
||||
if EnumPermissionsServer.COMMANDS in key_permissions:
|
||||
user_command_permission = True
|
||||
else:
|
||||
user_command_permission = False
|
||||
server_data.append(
|
||||
{
|
||||
"server_data": s,
|
||||
"stats": db_helper.return_rows(latest)[0],
|
||||
"server_data": server,
|
||||
"stats": DatabaseShortcuts.return_rows(latest)[0],
|
||||
"user_command_permission": user_command_permission,
|
||||
}
|
||||
)
|
||||
@ -131,22 +135,22 @@ class Servers_Controller:
|
||||
@staticmethod
|
||||
def get_authorized_servers_stats(user_id):
|
||||
server_data = []
|
||||
authorized_servers = Servers_Controller.get_authorized_servers(user_id)
|
||||
authorized_servers = ServersController.get_authorized_servers(user_id)
|
||||
|
||||
for s in authorized_servers:
|
||||
latest = servers_helper.get_latest_server_stats(s.get("server_id"))
|
||||
for server in authorized_servers:
|
||||
latest = HelperServerStats.get_latest_server_stats(server.get("server_id"))
|
||||
# TODO
|
||||
user_permissions = server_permissions.get_user_id_permissions_list(
|
||||
user_id, s.get("server_id")
|
||||
user_permissions = PermissionsServers.get_user_id_permissions_list(
|
||||
user_id, server.get("server_id")
|
||||
)
|
||||
if Enum_Permissions_Server.Commands in user_permissions:
|
||||
if EnumPermissionsServer.COMMANDS in user_permissions:
|
||||
user_command_permission = True
|
||||
else:
|
||||
user_command_permission = False
|
||||
server_data.append(
|
||||
{
|
||||
"server_data": s,
|
||||
"stats": db_helper.return_rows(latest)[0],
|
||||
"server_data": server,
|
||||
"stats": DatabaseShortcuts.return_rows(latest)[0],
|
||||
"user_command_permission": user_command_permission,
|
||||
}
|
||||
)
|
||||
@ -155,28 +159,28 @@ class Servers_Controller:
|
||||
|
||||
@staticmethod
|
||||
def get_server_friendly_name(server_id):
|
||||
return servers_helper.get_server_friendly_name(server_id)
|
||||
return HelperServers.get_server_friendly_name(server_id)
|
||||
|
||||
# **********************************************************************************
|
||||
# Servers_Stats Methods
|
||||
# **********************************************************************************
|
||||
@staticmethod
|
||||
def get_server_stats_by_id(server_id):
|
||||
return servers_helper.get_server_stats_by_id(server_id)
|
||||
return HelperServerStats.get_server_stats_by_id(server_id)
|
||||
|
||||
@staticmethod
|
||||
def server_id_exists(server_id):
|
||||
return servers_helper.server_id_exists(server_id)
|
||||
return HelperServerStats.server_id_exists(server_id)
|
||||
|
||||
@staticmethod
|
||||
def get_server_type_by_id(server_id):
|
||||
return servers_helper.get_server_type_by_id(server_id)
|
||||
return HelperServers.get_server_type_by_id(server_id)
|
||||
|
||||
@staticmethod
|
||||
def server_id_authorized(server_id_a, user_id):
|
||||
user_roles = users_helper.user_role_query(user_id)
|
||||
user_roles = HelperUsers.user_role_query(user_id)
|
||||
for role in user_roles:
|
||||
for server_id_b in server_permissions.get_role_servers_from_role_id(
|
||||
for server_id_b in PermissionsServers.get_role_servers_from_role_id(
|
||||
role.role_id
|
||||
):
|
||||
if str(server_id_a) == str(server_id_b.server_id):
|
||||
@ -185,51 +189,51 @@ class Servers_Controller:
|
||||
|
||||
@staticmethod
|
||||
def is_crashed(server_id):
|
||||
return servers_helper.is_crashed(server_id)
|
||||
return HelperServerStats.is_crashed(server_id)
|
||||
|
||||
@staticmethod
|
||||
def server_id_authorized_api_key(server_id: str, api_key: ApiKeys) -> bool:
|
||||
# TODO
|
||||
return Servers_Controller.server_id_authorized(server_id, api_key.user.user_id)
|
||||
return ServersController.server_id_authorized(server_id, api_key.user.user_id)
|
||||
# There is no view server permission
|
||||
# permission_helper.both_have_perm(api_key)
|
||||
|
||||
@staticmethod
|
||||
def set_update(server_id, value):
|
||||
return servers_helper.set_update(server_id, value)
|
||||
return HelperServerStats.set_update(server_id, value)
|
||||
|
||||
@staticmethod
|
||||
def get_TTL_without_player(server_id):
|
||||
return servers_helper.get_TTL_without_player(server_id)
|
||||
def get_ttl_without_player(server_id):
|
||||
return HelperServerStats.get_ttl_without_player(server_id)
|
||||
|
||||
@staticmethod
|
||||
def can_stop_no_players(server_id, time_limit):
|
||||
return servers_helper.can_stop_no_players(server_id, time_limit)
|
||||
return HelperServerStats.can_stop_no_players(server_id, time_limit)
|
||||
|
||||
@staticmethod
|
||||
def set_waiting_start(server_id, value):
|
||||
servers_helper.set_waiting_start(server_id, value)
|
||||
HelperServerStats.set_waiting_start(server_id, value)
|
||||
|
||||
@staticmethod
|
||||
def get_waiting_start(server_id):
|
||||
return servers_helper.get_waiting_start(server_id)
|
||||
return HelperServerStats.get_waiting_start(server_id)
|
||||
|
||||
@staticmethod
|
||||
def get_update_status(server_id):
|
||||
return servers_helper.get_update_status(server_id)
|
||||
return HelperServerStats.get_update_status(server_id)
|
||||
|
||||
# **********************************************************************************
|
||||
# Servers Helpers Methods
|
||||
# **********************************************************************************
|
||||
@staticmethod
|
||||
def get_banned_players(server_id):
|
||||
stats = servers_helper.get_server_stats_by_id(server_id)
|
||||
stats = HelperServerStats.get_server_stats_by_id(server_id)
|
||||
server_path = stats["server_id"]["path"]
|
||||
path = os.path.join(server_path, "banned-players.json")
|
||||
|
||||
try:
|
||||
with open(
|
||||
helper.get_os_understandable_path(path), encoding="utf-8"
|
||||
Helpers.get_os_understandable_path(path), encoding="utf-8"
|
||||
) as file:
|
||||
content = file.read()
|
||||
file.close()
|
||||
@ -240,7 +244,7 @@ class Servers_Controller:
|
||||
return json.loads(content)
|
||||
|
||||
def check_for_old_logs(self):
|
||||
servers = servers_helper.get_all_defined_servers()
|
||||
servers = HelperServers.get_all_defined_servers()
|
||||
for server in servers:
|
||||
logs_path = os.path.split(server["log_path"])[0]
|
||||
latest_log_file = os.path.split(server["log_path"])[1]
|
||||
@ -253,9 +257,9 @@ class Servers_Controller:
|
||||
)
|
||||
for log_file in log_files:
|
||||
log_file_path = os.path.join(logs_path, log_file)
|
||||
if helper.check_file_exists(
|
||||
if Helpers.check_file_exists(
|
||||
log_file_path
|
||||
) and helper.is_file_older_than_x_days(
|
||||
) and Helpers.is_file_older_than_x_days(
|
||||
log_file_path, logs_delete_after
|
||||
):
|
||||
os.remove(log_file_path)
|
||||
|
@ -1,61 +1,62 @@
|
||||
import logging
|
||||
from typing import Optional
|
||||
|
||||
from app.classes.models.users import users_helper
|
||||
from app.classes.models.users import HelperUsers
|
||||
from app.classes.models.crafty_permissions import (
|
||||
crafty_permissions,
|
||||
Enum_Permissions_Crafty,
|
||||
PermissionsCrafty,
|
||||
EnumPermissionsCrafty,
|
||||
)
|
||||
from app.classes.shared.helpers import helper
|
||||
from app.classes.shared.authentication import authentication
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Users_Controller:
|
||||
class UsersController:
|
||||
def __init__(self, helper, users_helper, authentication):
|
||||
self.helper = helper
|
||||
self.users_helper = users_helper
|
||||
self.authentication = authentication
|
||||
|
||||
# **********************************************************************************
|
||||
# Users Methods
|
||||
# **********************************************************************************
|
||||
@staticmethod
|
||||
def get_all_users():
|
||||
return users_helper.get_all_users()
|
||||
return HelperUsers.get_all_users()
|
||||
|
||||
@staticmethod
|
||||
def get_id_by_name(username):
|
||||
return users_helper.get_user_id_by_name(username)
|
||||
return HelperUsers.get_user_id_by_name(username)
|
||||
|
||||
@staticmethod
|
||||
def get_user_lang_by_id(user_id):
|
||||
return users_helper.get_user_lang_by_id(user_id)
|
||||
return HelperUsers.get_user_lang_by_id(user_id)
|
||||
|
||||
@staticmethod
|
||||
def get_user_by_id(user_id):
|
||||
return users_helper.get_user(user_id)
|
||||
return HelperUsers.get_user(user_id)
|
||||
|
||||
@staticmethod
|
||||
def update_server_order(user_id, user_server_order):
|
||||
users_helper.update_server_order(user_id, user_server_order)
|
||||
HelperUsers.update_server_order(user_id, user_server_order)
|
||||
|
||||
@staticmethod
|
||||
def get_server_order(user_id):
|
||||
return users_helper.get_server_order(user_id)
|
||||
return HelperUsers.get_server_order(user_id)
|
||||
|
||||
@staticmethod
|
||||
def user_query(user_id):
|
||||
return users_helper.user_query(user_id)
|
||||
return HelperUsers.user_query(user_id)
|
||||
|
||||
@staticmethod
|
||||
def set_support_path(user_id, support_path):
|
||||
users_helper.set_support_path(user_id, support_path)
|
||||
HelperUsers.set_support_path(user_id, support_path)
|
||||
|
||||
@staticmethod
|
||||
def update_user(user_id: str, user_data=None, user_crafty_data=None):
|
||||
def update_user(self, user_id: str, user_data=None, user_crafty_data=None):
|
||||
if user_crafty_data is None:
|
||||
user_crafty_data = {}
|
||||
if user_data is None:
|
||||
user_data = {}
|
||||
base_data = users_helper.get_user(user_id)
|
||||
base_data = HelperUsers.get_user(user_id)
|
||||
up_data = {}
|
||||
added_roles = set()
|
||||
removed_roles = set()
|
||||
@ -67,53 +68,54 @@ class Users_Controller:
|
||||
removed_roles = base_data["roles"].difference(user_data["roles"])
|
||||
elif key == "password":
|
||||
if user_data["password"] is not None and user_data["password"] != "":
|
||||
up_data["password"] = helper.encode_pass(user_data["password"])
|
||||
up_data["password"] = self.helper.encode_pass(user_data["password"])
|
||||
elif base_data[key] != user_data[key]:
|
||||
up_data[key] = user_data[key]
|
||||
up_data["last_update"] = helper.get_time_as_string()
|
||||
up_data["last_update"] = self.helper.get_time_as_string()
|
||||
up_data["lang"] = user_data["lang"]
|
||||
up_data["hints"] = user_data["hints"]
|
||||
logger.debug(f"user: {user_data} +role:{added_roles} -role:{removed_roles}")
|
||||
for role in added_roles:
|
||||
users_helper.get_or_create(user_id=user_id, role_id=role)
|
||||
permissions_mask = user_crafty_data.get("permissions_mask", "000")
|
||||
HelperUsers.get_or_create(user_id=user_id, role_id=role)
|
||||
permissions_mask = user_crafty_data.get("permissions_mask", "000")
|
||||
|
||||
if "server_quantity" in user_crafty_data:
|
||||
limit_server_creation = user_crafty_data["server_quantity"][
|
||||
Enum_Permissions_Crafty.Server_Creation.name
|
||||
]
|
||||
if "server_quantity" in user_crafty_data:
|
||||
limit_server_creation = user_crafty_data["server_quantity"][
|
||||
EnumPermissionsCrafty.SERVER_CREATION.name
|
||||
]
|
||||
|
||||
limit_user_creation = user_crafty_data["server_quantity"][
|
||||
Enum_Permissions_Crafty.User_Config.name
|
||||
]
|
||||
limit_role_creation = user_crafty_data["server_quantity"][
|
||||
Enum_Permissions_Crafty.Roles_Config.name
|
||||
]
|
||||
else:
|
||||
limit_server_creation = 0
|
||||
limit_user_creation = 0
|
||||
limit_role_creation = 0
|
||||
limit_user_creation = user_crafty_data["server_quantity"][
|
||||
EnumPermissionsCrafty.USER_CONFIG.name
|
||||
]
|
||||
limit_role_creation = user_crafty_data["server_quantity"][
|
||||
EnumPermissionsCrafty.ROLES_CONFIG.name
|
||||
]
|
||||
else:
|
||||
limit_server_creation = 0
|
||||
limit_user_creation = 0
|
||||
limit_role_creation = 0
|
||||
|
||||
crafty_permissions.add_or_update_user(
|
||||
user_id,
|
||||
permissions_mask,
|
||||
limit_server_creation,
|
||||
limit_user_creation,
|
||||
limit_role_creation,
|
||||
)
|
||||
PermissionsCrafty.add_or_update_user(
|
||||
user_id,
|
||||
permissions_mask,
|
||||
limit_server_creation,
|
||||
limit_user_creation,
|
||||
limit_role_creation,
|
||||
)
|
||||
|
||||
users_helper.delete_user_roles(user_id, removed_roles)
|
||||
self.users_helper.delete_user_roles(user_id, removed_roles)
|
||||
|
||||
users_helper.update_user(user_id, up_data)
|
||||
self.users_helper.update_user(user_id, up_data)
|
||||
|
||||
@staticmethod
|
||||
def add_user(
|
||||
self,
|
||||
username,
|
||||
password,
|
||||
email="default@example.com",
|
||||
enabled: bool = True,
|
||||
superuser: bool = False,
|
||||
):
|
||||
return users_helper.add_user(
|
||||
return self.users_helper.add_user(
|
||||
username,
|
||||
password=password,
|
||||
email=email,
|
||||
@ -129,7 +131,7 @@ class Users_Controller:
|
||||
enabled: bool = True,
|
||||
superuser: bool = False,
|
||||
):
|
||||
return users_helper.add_rawpass_user(
|
||||
return HelperUsers.add_rawpass_user(
|
||||
username,
|
||||
password=password,
|
||||
email=email,
|
||||
@ -137,55 +139,54 @@ class Users_Controller:
|
||||
superuser=superuser,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def remove_user(user_id):
|
||||
return users_helper.remove_user(user_id)
|
||||
def remove_user(self, user_id):
|
||||
return self.users_helper.remove_user(user_id)
|
||||
|
||||
@staticmethod
|
||||
def user_id_exists(user_id):
|
||||
return users_helper.user_id_exists(user_id)
|
||||
return HelperUsers.user_id_exists(user_id)
|
||||
|
||||
@staticmethod
|
||||
def set_prepare(user_id):
|
||||
return users_helper.set_prepare(user_id)
|
||||
return HelperUsers.set_prepare(user_id)
|
||||
|
||||
@staticmethod
|
||||
def stop_prepare(user_id):
|
||||
return users_helper.stop_prepare(user_id)
|
||||
return HelperUsers.stop_prepare(user_id)
|
||||
|
||||
@staticmethod
|
||||
def get_user_id_by_api_token(token: str) -> str:
|
||||
token_data = authentication.check_no_iat(token)
|
||||
def get_user_id_by_api_token(self, token: str) -> str:
|
||||
token_data = self.authentication.check_no_iat(token)
|
||||
return token_data["user_id"]
|
||||
|
||||
@staticmethod
|
||||
def get_user_by_api_token(token: str):
|
||||
_, user = authentication.check(token)
|
||||
def get_user_by_api_token(self, token: str):
|
||||
_, _, user = self.authentication.check(token)
|
||||
return user
|
||||
|
||||
def get_api_key_by_token(self, token: str):
|
||||
key, _, _ = self.authentication.check(token)
|
||||
return key
|
||||
|
||||
# **********************************************************************************
|
||||
# User Roles Methods
|
||||
# **********************************************************************************
|
||||
|
||||
@staticmethod
|
||||
def get_user_roles_id(user_id):
|
||||
return users_helper.get_user_roles_id(user_id)
|
||||
return HelperUsers.get_user_roles_id(user_id)
|
||||
|
||||
@staticmethod
|
||||
def get_user_roles_names(user_id):
|
||||
return users_helper.get_user_roles_names(user_id)
|
||||
return HelperUsers.get_user_roles_names(user_id)
|
||||
|
||||
@staticmethod
|
||||
def add_role_to_user(user_id, role_id):
|
||||
return users_helper.add_role_to_user(user_id, role_id)
|
||||
def add_role_to_user(self, user_id, role_id):
|
||||
return self.users_helper.add_role_to_user(user_id, role_id)
|
||||
|
||||
@staticmethod
|
||||
def add_user_roles(user):
|
||||
return users_helper.add_user_roles(user)
|
||||
def add_user_roles(self, user):
|
||||
return self.users_helper.add_user_roles(user)
|
||||
|
||||
@staticmethod
|
||||
def user_role_query(user_id):
|
||||
return users_helper.user_role_query(user_id)
|
||||
return HelperUsers.user_role_query(user_id)
|
||||
|
||||
# **********************************************************************************
|
||||
# Api Keys Methods
|
||||
@ -193,28 +194,26 @@ class Users_Controller:
|
||||
|
||||
@staticmethod
|
||||
def get_user_api_keys(user_id: str):
|
||||
return users_helper.get_user_api_keys(user_id)
|
||||
return HelperUsers.get_user_api_keys(user_id)
|
||||
|
||||
@staticmethod
|
||||
def get_user_api_key(key_id: str):
|
||||
return users_helper.get_user_api_key(key_id)
|
||||
return HelperUsers.get_user_api_key(key_id)
|
||||
|
||||
@staticmethod
|
||||
def add_user_api_key(
|
||||
self,
|
||||
name: str,
|
||||
user_id: str,
|
||||
superuser: bool = False,
|
||||
server_permissions_mask: Optional[str] = None,
|
||||
crafty_permissions_mask: Optional[str] = None,
|
||||
):
|
||||
return users_helper.add_user_api_key(
|
||||
return self.users_helper.add_user_api_key(
|
||||
name, user_id, superuser, server_permissions_mask, crafty_permissions_mask
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def delete_user_api_keys(user_id: str):
|
||||
return users_helper.delete_user_api_keys(user_id)
|
||||
def delete_user_api_keys(self, user_id: str):
|
||||
return self.users_helper.delete_user_api_keys(user_id)
|
||||
|
||||
@staticmethod
|
||||
def delete_user_api_key(key_id: str):
|
||||
return users_helper.delete_user_api_key(key_id)
|
||||
def delete_user_api_key(self, key_id: str):
|
||||
return self.users_helper.delete_user_api_key(key_id)
|
||||
|
@ -37,34 +37,45 @@ class BedrockPing:
|
||||
@staticmethod
|
||||
def __slice(in_bytes, pattern):
|
||||
ret = []
|
||||
bi = 0 # bytes index
|
||||
pi = 0 # pattern index
|
||||
while bi < len(in_bytes):
|
||||
bytes_index = 0
|
||||
pattern_index = 0
|
||||
while bytes_index < len(in_bytes):
|
||||
try:
|
||||
f = BedrockPing.fields[pattern[pi]]
|
||||
field = BedrockPing.fields[pattern[pattern_index]]
|
||||
except IndexError as index_error:
|
||||
raise IndexError(
|
||||
"Ran out of pattern with additional bytes remaining"
|
||||
) from index_error
|
||||
if pattern[pi] == "string":
|
||||
shl = f[0] # string header length
|
||||
sl = int.from_bytes(
|
||||
in_bytes[bi : bi + shl], BedrockPing.byte_order, signed=f[1]
|
||||
) # string length
|
||||
l = shl + sl
|
||||
ret.append(in_bytes[bi + shl : bi + shl + sl].decode("ascii"))
|
||||
elif pattern[pi] == "magic":
|
||||
l = f[0] # length of field
|
||||
ret.append(in_bytes[bi : bi + l])
|
||||
if pattern[pattern_index] == "string":
|
||||
string_header_length = field[0]
|
||||
string_length = int.from_bytes(
|
||||
in_bytes[bytes_index : bytes_index + string_header_length],
|
||||
BedrockPing.byte_order,
|
||||
signed=field[1],
|
||||
)
|
||||
length = string_header_length + string_length
|
||||
ret.append(
|
||||
in_bytes[
|
||||
bytes_index
|
||||
+ string_header_length : bytes_index
|
||||
+ string_header_length
|
||||
+ string_length
|
||||
].decode("ascii")
|
||||
)
|
||||
elif pattern[pattern_index] == "magic":
|
||||
length = field[0]
|
||||
ret.append(in_bytes[bytes_index : bytes_index + length])
|
||||
else:
|
||||
l = f[0] # length of field
|
||||
length = field[0]
|
||||
ret.append(
|
||||
int.from_bytes(
|
||||
in_bytes[bi : bi + l], BedrockPing.byte_order, signed=f[1]
|
||||
in_bytes[bytes_index : bytes_index + length],
|
||||
BedrockPing.byte_order,
|
||||
signed=field[1],
|
||||
)
|
||||
)
|
||||
bi += l
|
||||
pi += 1
|
||||
bytes_index += length
|
||||
pattern_index += 1
|
||||
return ret
|
||||
|
||||
@staticmethod
|
||||
@ -115,6 +126,6 @@ class BedrockPing:
|
||||
return self.__recvpong()
|
||||
except ValueError as e:
|
||||
print(
|
||||
f"E: {e}, checking next packet. Retries remaining: {rtr}/{retries}"
|
||||
f"E: {e}, checking next packet. Retries remaining: {rtr}/{retries}"
|
||||
)
|
||||
rtr -= 1
|
||||
|
@ -9,7 +9,7 @@ import uuid
|
||||
import random
|
||||
|
||||
from app.classes.minecraft.bedrock_ping import BedrockPing
|
||||
from app.classes.shared.console import console
|
||||
from app.classes.shared.console import Console
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@ -78,8 +78,8 @@ class Players(list):
|
||||
def report(self):
|
||||
players = []
|
||||
|
||||
for x in self:
|
||||
players.append(str(x))
|
||||
for player in self:
|
||||
players.append(str(player))
|
||||
|
||||
r_data = {"online": self.online, "max": self.max, "players": players}
|
||||
|
||||
@ -106,14 +106,14 @@ def get_code_format(format_name):
|
||||
return data.get(format_name)
|
||||
else:
|
||||
logger.error(f"Format MOTD Error: format name {format_name} does not exist")
|
||||
console.error(
|
||||
Console.error(
|
||||
f"Format MOTD Error: format name {format_name} does not exist"
|
||||
)
|
||||
return ""
|
||||
|
||||
except Exception as e:
|
||||
logger.critical(f"Config File Error: Unable to read {format_file} due to {e}")
|
||||
console.critical(f"Config File Error: Unable to read {format_file} due to {e}")
|
||||
Console.critical(f"Config File Error: Unable to read {format_file} due to {e}")
|
||||
|
||||
return ""
|
||||
|
||||
@ -179,11 +179,11 @@ def ping(ip, port):
|
||||
|
||||
# For the rest of requests see wiki.vg/Protocol
|
||||
def ping_bedrock(ip, port):
|
||||
rd = random.Random()
|
||||
rand = random.Random()
|
||||
try:
|
||||
# pylint: disable=consider-using-f-string
|
||||
rd.seed("".join(re.findall("..", "%012x" % uuid.getnode())))
|
||||
client_guid = uuid.UUID(int=rd.getrandbits(32)).int
|
||||
rand.seed("".join(re.findall("..", "%012x" % uuid.getnode())))
|
||||
client_guid = uuid.UUID(int=rand.getrandbits(32)).int
|
||||
except:
|
||||
client_guid = 0
|
||||
try:
|
||||
|
@ -9,25 +9,25 @@ class ServerProps:
|
||||
|
||||
def _parse(self):
|
||||
# Loads and parses the file specified in self.filepath
|
||||
with open(self.filepath, encoding="utf-8") as fp:
|
||||
line = fp.readline()
|
||||
d = {}
|
||||
with open(self.filepath, encoding="utf-8") as full_path:
|
||||
line = full_path.readline()
|
||||
dictionary = {}
|
||||
if os.path.exists(".header"):
|
||||
os.remove(".header")
|
||||
while line:
|
||||
if "#" != line[0]:
|
||||
s = line
|
||||
s1 = s[: s.find("=")]
|
||||
if "\n" in s:
|
||||
s2 = s[s.find("=") + 1 : s.find("\n")]
|
||||
string = line
|
||||
string1 = string[: string.find("=")]
|
||||
if "\n" in string:
|
||||
string2 = string[string.find("=") + 1 : string.find("\n")]
|
||||
else:
|
||||
s2 = s[s.find("=") + 1 :]
|
||||
d[s1] = s2
|
||||
string2 = string[string.find("=") + 1 :]
|
||||
dictionary[string1] = string2
|
||||
else:
|
||||
with open(".header", "a+", encoding="utf-8") as h:
|
||||
h.write(line)
|
||||
line = fp.readline()
|
||||
return d
|
||||
with open(".header", "a+", encoding="utf-8") as header:
|
||||
header.write(line)
|
||||
line = full_path.readline()
|
||||
return dictionary
|
||||
|
||||
def print(self):
|
||||
# Prints the properties dictionary (using pprint)
|
||||
|
@ -4,39 +4,33 @@ import time
|
||||
import shutil
|
||||
import logging
|
||||
from datetime import datetime
|
||||
import requests
|
||||
|
||||
from app.classes.controllers.servers_controller import Servers_Controller
|
||||
from app.classes.models.server_permissions import server_permissions
|
||||
from app.classes.shared.helpers import helper
|
||||
from app.classes.web.websocket_helper import websocket_helper
|
||||
from app.classes.controllers.servers_controller import ServersController
|
||||
from app.classes.models.server_permissions import PermissionsServers
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
try:
|
||||
import requests
|
||||
|
||||
except ModuleNotFoundError as err:
|
||||
helper.auto_installer_fix(err)
|
||||
|
||||
|
||||
class ServerJars:
|
||||
def __init__(self):
|
||||
def __init__(self, helper):
|
||||
self.helper = helper
|
||||
self.base_url = "https://serverjars.com"
|
||||
|
||||
def _get_api_result(self, call_url: str):
|
||||
full_url = f"{self.base_url}{call_url}"
|
||||
|
||||
try:
|
||||
r = requests.get(full_url, timeout=2)
|
||||
response = requests.get(full_url, timeout=2)
|
||||
|
||||
if r.status_code not in [200, 201]:
|
||||
if response.status_code not in [200, 201]:
|
||||
return {}
|
||||
except Exception as e:
|
||||
logger.error(f"Unable to connect to serverjar.com api due to error: {e}")
|
||||
return {}
|
||||
|
||||
try:
|
||||
api_data = json.loads(r.content)
|
||||
api_data = json.loads(response.content)
|
||||
except Exception as e:
|
||||
logger.error(f"Unable to parse serverjar.com api result due to error: {e}")
|
||||
return {}
|
||||
@ -50,9 +44,8 @@ class ServerJars:
|
||||
|
||||
return api_response
|
||||
|
||||
@staticmethod
|
||||
def _read_cache():
|
||||
cache_file = helper.serverjar_cache
|
||||
def _read_cache(self):
|
||||
cache_file = self.helper.serverjar_cache
|
||||
cache = {}
|
||||
try:
|
||||
with open(cache_file, "r", encoding="utf-8") as f:
|
||||
@ -67,37 +60,14 @@ class ServerJars:
|
||||
data = self._read_cache()
|
||||
return data.get("servers")
|
||||
|
||||
def get_serverjar_data_sorted(self):
|
||||
data = self.get_serverjar_data()
|
||||
|
||||
def str_to_int(x, counter=0):
|
||||
try:
|
||||
return ord(x[0]) + str_to_int(x[1:], counter + 1) + len(x)
|
||||
except IndexError:
|
||||
return 0
|
||||
|
||||
def to_int(x):
|
||||
try:
|
||||
return int(x)
|
||||
except ValueError:
|
||||
temp = x.split("-")
|
||||
return to_int(temp[0]) + str_to_int(temp[1]) / 100000
|
||||
|
||||
sort_key_fn = lambda x: [to_int(y) for y in x.split(".")]
|
||||
|
||||
for key in data.keys():
|
||||
data[key] = sorted(data[key], key=sort_key_fn)
|
||||
|
||||
return data
|
||||
|
||||
def _check_api_alive(self):
|
||||
logger.info("Checking serverjars.com API status")
|
||||
|
||||
check_url = f"{self.base_url}/api/fetchTypes"
|
||||
try:
|
||||
r = requests.get(check_url, timeout=2)
|
||||
response = requests.get(check_url, timeout=2)
|
||||
|
||||
if r.status_code in [200, 201]:
|
||||
if response.status_code in [200, 201]:
|
||||
logger.info("Serverjars.com API is alive")
|
||||
return True
|
||||
except Exception as e:
|
||||
@ -109,8 +79,8 @@ class ServerJars:
|
||||
|
||||
def refresh_cache(self):
|
||||
|
||||
cache_file = helper.serverjar_cache
|
||||
cache_old = helper.is_file_older_than_x_days(cache_file)
|
||||
cache_file = self.helper.serverjar_cache
|
||||
cache_old = self.helper.is_file_older_than_x_days(cache_file)
|
||||
|
||||
# debug override
|
||||
# cache_old = True
|
||||
@ -166,6 +136,7 @@ class ServerJars:
|
||||
|
||||
def download_jar(self, server, version, path, server_id):
|
||||
update_thread = threading.Thread(
|
||||
name=f"server_download-{server_id}-{server}-{version}",
|
||||
target=self.a_download_jar,
|
||||
daemon=True,
|
||||
args=(server, version, path, server_id),
|
||||
@ -176,46 +147,49 @@ class ServerJars:
|
||||
# delaying download for server register to finish
|
||||
time.sleep(3)
|
||||
fetch_url = f"{self.base_url}/api/fetchJar/{server}/{version}"
|
||||
server_users = server_permissions.get_server_user_list(server_id)
|
||||
server_users = PermissionsServers.get_server_user_list(server_id)
|
||||
|
||||
# We need to make sure the server is registered before
|
||||
# we submit a db update for it's stats.
|
||||
while True:
|
||||
try:
|
||||
Servers_Controller.set_download(server_id)
|
||||
ServersController.set_download(server_id)
|
||||
for user in server_users:
|
||||
websocket_helper.broadcast_user(user, "send_start_reload", {})
|
||||
self.helper.websocket_helper.broadcast_user(
|
||||
user, "send_start_reload", {}
|
||||
)
|
||||
|
||||
break
|
||||
except:
|
||||
logger.debug("server not registered yet. Delaying download.")
|
||||
except Exception as ex:
|
||||
logger.debug(f"server not registered yet. Delaying download - {ex}")
|
||||
|
||||
# open a file stream
|
||||
with requests.get(fetch_url, timeout=2, stream=True) as r:
|
||||
try:
|
||||
with open(path, "wb") as output:
|
||||
shutil.copyfileobj(r.raw, output)
|
||||
Servers_Controller.finish_download(server_id)
|
||||
ServersController.finish_download(server_id)
|
||||
|
||||
for user in server_users:
|
||||
websocket_helper.broadcast_user(
|
||||
self.helper.websocket_helper.broadcast_user(
|
||||
user, "notification", "Executable download finished"
|
||||
)
|
||||
time.sleep(3)
|
||||
websocket_helper.broadcast_user(user, "send_start_reload", {})
|
||||
self.helper.websocket_helper.broadcast_user(
|
||||
user, "send_start_reload", {}
|
||||
)
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error(f"Unable to save jar to {path} due to error:{e}")
|
||||
Servers_Controller.finish_download(server_id)
|
||||
server_users = server_permissions.get_server_user_list(server_id)
|
||||
ServersController.finish_download(server_id)
|
||||
server_users = PermissionsServers.get_server_user_list(server_id)
|
||||
for user in server_users:
|
||||
websocket_helper.broadcast_user(
|
||||
self.helper.websocket_helper.broadcast_user(
|
||||
user, "notification", "Executable download finished"
|
||||
)
|
||||
time.sleep(3)
|
||||
websocket_helper.broadcast_user(user, "send_start_reload", {})
|
||||
self.helper.websocket_helper.broadcast_user(
|
||||
user, "send_start_reload", {}
|
||||
)
|
||||
|
||||
return False
|
||||
|
||||
|
||||
server_jar_obj = ServerJars()
|
||||
|
@ -5,15 +5,16 @@ import base64
|
||||
import psutil
|
||||
|
||||
from app.classes.minecraft.mc_ping import ping
|
||||
from app.classes.models.management import Host_Stats
|
||||
from app.classes.models.servers import servers_helper
|
||||
from app.classes.shared.helpers import helper
|
||||
from app.classes.models.management import HostStats
|
||||
from app.classes.models.servers import HelperServers
|
||||
from app.classes.shared.helpers import Helpers
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Stats:
|
||||
def __init__(self, controller):
|
||||
def __init__(self, helper, controller):
|
||||
self.helper = helper
|
||||
self.controller = controller
|
||||
|
||||
def get_node_stats(self):
|
||||
@ -30,8 +31,8 @@ class Stats:
|
||||
"cpu_cur_freq": round(cpu_freq[0], 2),
|
||||
"cpu_max_freq": cpu_freq[2],
|
||||
"mem_percent": psutil.virtual_memory()[2],
|
||||
"mem_usage": helper.human_readable_file_size(psutil.virtual_memory()[3]),
|
||||
"mem_total": helper.human_readable_file_size(psutil.virtual_memory()[0]),
|
||||
"mem_usage": Helpers.human_readable_file_size(psutil.virtual_memory()[3]),
|
||||
"mem_total": Helpers.human_readable_file_size(psutil.virtual_memory()[0]),
|
||||
"disk_data": self._all_disk_usage(),
|
||||
}
|
||||
# server_stats = self.get_servers_stats()
|
||||
@ -60,7 +61,9 @@ class Stats:
|
||||
with p.oneshot():
|
||||
process_stats = {
|
||||
"cpu_usage": real_cpu,
|
||||
"memory_usage": helper.human_readable_file_size(p.memory_info()[0]),
|
||||
"memory_usage": Helpers.human_readable_file_size(
|
||||
p.memory_info()[0]
|
||||
),
|
||||
"mem_percentage": round(p.memory_percent(), 0),
|
||||
}
|
||||
return process_stats
|
||||
@ -84,7 +87,7 @@ class Stats:
|
||||
# print(templ % ("Device", "Total", "Used", "Free", "Use ", "Type","Mount"))
|
||||
|
||||
for part in psutil.disk_partitions(all=False):
|
||||
if helper.is_os_windows():
|
||||
if Helpers.is_os_windows():
|
||||
if "cdrom" in part.opts or part.fstype == "":
|
||||
# skip cd-rom drives with no disk in it; they may raise
|
||||
# ENOENT, pop-up a Windows GUI error for a non-ready
|
||||
@ -94,9 +97,9 @@ class Stats:
|
||||
disk_data.append(
|
||||
{
|
||||
"device": part.device,
|
||||
"total": helper.human_readable_file_size(usage.total),
|
||||
"used": helper.human_readable_file_size(usage.used),
|
||||
"free": helper.human_readable_file_size(usage.free),
|
||||
"total": Helpers.human_readable_file_size(usage.total),
|
||||
"used": Helpers.human_readable_file_size(usage.used),
|
||||
"free": Helpers.human_readable_file_size(usage.free),
|
||||
"percent_used": int(usage.percent),
|
||||
"fs": part.fstype,
|
||||
"mount": part.mountpoint,
|
||||
@ -110,15 +113,15 @@ class Stats:
|
||||
|
||||
total_size = 0
|
||||
|
||||
total_size = helper.get_dir_size(server_path)
|
||||
total_size = Helpers.get_dir_size(server_path)
|
||||
|
||||
level_total_size = helper.human_readable_file_size(total_size)
|
||||
level_total_size = Helpers.human_readable_file_size(total_size)
|
||||
|
||||
return level_total_size
|
||||
|
||||
def get_server_players(self, server_id):
|
||||
|
||||
server = servers_helper.get_server_data_by_id(server_id)
|
||||
server = HelperServers.get_server_data_by_id(server_id)
|
||||
|
||||
logger.info(f"Getting players for server {server}")
|
||||
|
||||
@ -130,8 +133,8 @@ class Stats:
|
||||
internal_ip = server["server_ip"]
|
||||
server_port = server["server_port"]
|
||||
|
||||
logger.debug("Pinging {internal_ip} on port {server_port}")
|
||||
if servers_helper.get_server_type_by_id(server_id) != "minecraft-bedrock":
|
||||
logger.debug(f"Pinging {internal_ip} on port {server_port}")
|
||||
if HelperServers.get_server_type_by_id(server_id) != "minecraft-bedrock":
|
||||
int_mc_ping = ping(internal_ip, int(server_port))
|
||||
|
||||
ping_data = {}
|
||||
@ -171,7 +174,7 @@ class Stats:
|
||||
return ping_data
|
||||
|
||||
@staticmethod
|
||||
def parse_server_RakNet_ping(ping_obj: object):
|
||||
def parse_server_raknet_ping(ping_obj: object):
|
||||
|
||||
try:
|
||||
server_icon = base64.encodebytes(ping_obj["icon"])
|
||||
@ -193,50 +196,23 @@ class Stats:
|
||||
stats_to_send = self.get_node_stats()
|
||||
node_stats = stats_to_send.get("node_stats")
|
||||
|
||||
Host_Stats.insert(
|
||||
HostStats.insert(
|
||||
{
|
||||
Host_Stats.boot_time: node_stats.get("boot_time", "Unknown"),
|
||||
Host_Stats.cpu_usage: round(node_stats.get("cpu_usage", 0), 2),
|
||||
Host_Stats.cpu_cores: node_stats.get("cpu_count", 0),
|
||||
Host_Stats.cpu_cur_freq: node_stats.get("cpu_cur_freq", 0),
|
||||
Host_Stats.cpu_max_freq: node_stats.get("cpu_max_freq", 0),
|
||||
Host_Stats.mem_usage: node_stats.get("mem_usage", "0 MB"),
|
||||
Host_Stats.mem_percent: node_stats.get("mem_percent", 0),
|
||||
Host_Stats.mem_total: node_stats.get("mem_total", "0 MB"),
|
||||
Host_Stats.disk_json: node_stats.get("disk_data", "{}"),
|
||||
HostStats.boot_time: node_stats.get("boot_time", "Unknown"),
|
||||
HostStats.cpu_usage: round(node_stats.get("cpu_usage", 0), 2),
|
||||
HostStats.cpu_cores: node_stats.get("cpu_count", 0),
|
||||
HostStats.cpu_cur_freq: node_stats.get("cpu_cur_freq", 0),
|
||||
HostStats.cpu_max_freq: node_stats.get("cpu_max_freq", 0),
|
||||
HostStats.mem_usage: node_stats.get("mem_usage", "0 MB"),
|
||||
HostStats.mem_percent: node_stats.get("mem_percent", 0),
|
||||
HostStats.mem_total: node_stats.get("mem_total", "0 MB"),
|
||||
HostStats.disk_json: node_stats.get("disk_data", "{}"),
|
||||
}
|
||||
).execute()
|
||||
|
||||
# server_stats = stats_to_send.get("servers")
|
||||
# for server in server_stats:
|
||||
# Server_Stats.insert(
|
||||
# {
|
||||
# Server_Stats.server_id: server.get("id", 0),
|
||||
# Server_Stats.started: server.get("started", ""),
|
||||
# Server_Stats.running: server.get("running", False),
|
||||
# Server_Stats.cpu: server.get("cpu", 0),
|
||||
# Server_Stats.mem: server.get("mem", 0),
|
||||
# Server_Stats.mem_percent: server.get("mem_percent", 0),
|
||||
# Server_Stats.world_name: server.get("world_name", ""),
|
||||
# Server_Stats.world_size: server.get("world_size", ""),
|
||||
# Server_Stats.server_port: server.get("server_port", ""),
|
||||
# Server_Stats.int_ping_results: server.get(
|
||||
# "int_ping_results", False
|
||||
# ),
|
||||
# Server_Stats.online: server.get("online", False),
|
||||
# Server_Stats.max: server.get("max", False),
|
||||
# Server_Stats.players: server.get("players", False),
|
||||
# Server_Stats.desc: server.get("desc", False),
|
||||
# Server_Stats.version: server.get("version", False),
|
||||
# }
|
||||
# ).execute()
|
||||
|
||||
# delete old data
|
||||
max_age = helper.get_setting("history_max_age")
|
||||
max_age = self.helper.get_setting("history_max_age")
|
||||
now = datetime.datetime.now()
|
||||
last_week = now.day - max_age
|
||||
|
||||
Host_Stats.delete().where(Host_Stats.time < last_week).execute()
|
||||
|
||||
|
||||
# Server_Stats.delete().where(Server_Stats.created < last_week).execute()
|
||||
HostStats.delete().where(HostStats.time < last_week).execute()
|
||||
|
8
app/classes/models/base_model.py
Normal file
8
app/classes/models/base_model.py
Normal file
@ -0,0 +1,8 @@
|
||||
import peewee
|
||||
|
||||
database_proxy = peewee.DatabaseProxy()
|
||||
|
||||
|
||||
class BaseModel(peewee.Model):
|
||||
class Meta:
|
||||
database = database_proxy
|
@ -1,35 +1,22 @@
|
||||
import logging
|
||||
|
||||
from app.classes.shared.helpers import helper
|
||||
from app.classes.shared.permission_helper import permission_helper
|
||||
from app.classes.models.users import Users, ApiKeys
|
||||
|
||||
try:
|
||||
from peewee import (
|
||||
SqliteDatabase,
|
||||
Model,
|
||||
ForeignKeyField,
|
||||
CharField,
|
||||
IntegerField,
|
||||
DoesNotExist,
|
||||
)
|
||||
from enum import Enum
|
||||
|
||||
except ModuleNotFoundError as e:
|
||||
helper.auto_installer_fix(e)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
peewee_logger = logging.getLogger("peewee")
|
||||
peewee_logger.setLevel(logging.INFO)
|
||||
database = SqliteDatabase(
|
||||
helper.db_path, pragmas={"journal_mode": "wal", "cache_size": -1024 * 10}
|
||||
from enum import Enum
|
||||
from peewee import (
|
||||
ForeignKeyField,
|
||||
CharField,
|
||||
IntegerField,
|
||||
DoesNotExist,
|
||||
)
|
||||
|
||||
from app.classes.models.base_model import BaseModel
|
||||
from app.classes.models.users import Users, ApiKeys, HelperUsers
|
||||
from app.classes.shared.permission_helper import PermissionHelper
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# **********************************************************************************
|
||||
# User_Crafty Class
|
||||
# **********************************************************************************
|
||||
class User_Crafty(Model):
|
||||
class UserCrafty(BaseModel):
|
||||
user_id = ForeignKeyField(Users, backref="users_crafty")
|
||||
permissions = CharField(default="00000000")
|
||||
limit_server_creation = IntegerField(default=-1)
|
||||
@ -41,39 +28,38 @@ class User_Crafty(Model):
|
||||
|
||||
class Meta:
|
||||
table_name = "user_crafty"
|
||||
database = database
|
||||
|
||||
|
||||
# **********************************************************************************
|
||||
# Crafty Permissions Class
|
||||
# **********************************************************************************
|
||||
class Enum_Permissions_Crafty(Enum):
|
||||
Server_Creation = 0
|
||||
User_Config = 1
|
||||
Roles_Config = 2
|
||||
class EnumPermissionsCrafty(Enum):
|
||||
SERVER_CREATION = 0
|
||||
USER_CONFIG = 1
|
||||
ROLES_CONFIG = 2
|
||||
|
||||
|
||||
class Permissions_Crafty:
|
||||
class PermissionsCrafty:
|
||||
# **********************************************************************************
|
||||
# Crafty Permissions Methods
|
||||
# **********************************************************************************
|
||||
@staticmethod
|
||||
def get_permissions_list():
|
||||
permissions_list = []
|
||||
for member in Enum_Permissions_Crafty.__members__.items():
|
||||
for member in EnumPermissionsCrafty.__members__.items():
|
||||
permissions_list.append(member[1])
|
||||
return permissions_list
|
||||
|
||||
@staticmethod
|
||||
def get_permissions(permissions_mask):
|
||||
permissions_list = []
|
||||
for member in Enum_Permissions_Crafty.__members__.items():
|
||||
if crafty_permissions.has_permission(permissions_mask, member[1]):
|
||||
for member in EnumPermissionsCrafty.__members__.items():
|
||||
if PermissionsCrafty.has_permission(permissions_mask, member[1]):
|
||||
permissions_list.append(member[1])
|
||||
return permissions_list
|
||||
|
||||
@staticmethod
|
||||
def has_permission(permission_mask, permission_tested: Enum_Permissions_Crafty):
|
||||
def has_permission(permission_mask, permission_tested: EnumPermissionsCrafty):
|
||||
result = False
|
||||
if permission_mask[permission_tested.value] == "1":
|
||||
result = True
|
||||
@ -81,40 +67,40 @@ class Permissions_Crafty:
|
||||
|
||||
@staticmethod
|
||||
def set_permission(
|
||||
permission_mask, permission_tested: Enum_Permissions_Crafty, value
|
||||
permission_mask, permission_tested: EnumPermissionsCrafty, value
|
||||
):
|
||||
l = list(permission_mask)
|
||||
l[permission_tested.value] = str(value)
|
||||
permission_mask = "".join(l)
|
||||
lst = list(permission_mask)
|
||||
lst[permission_tested.value] = str(value)
|
||||
permission_mask = "".join(lst)
|
||||
return permission_mask
|
||||
|
||||
@staticmethod
|
||||
def get_permission(permission_mask, permission_tested: Enum_Permissions_Crafty):
|
||||
def get_permission(permission_mask, permission_tested: EnumPermissionsCrafty):
|
||||
return permission_mask[permission_tested.value]
|
||||
|
||||
@staticmethod
|
||||
def get_crafty_permissions_mask(user_id):
|
||||
permissions_mask = ""
|
||||
user_crafty = crafty_permissions.get_User_Crafty(user_id)
|
||||
user_crafty = PermissionsCrafty.get_user_crafty(user_id)
|
||||
permissions_mask = user_crafty.permissions
|
||||
return permissions_mask
|
||||
|
||||
@staticmethod
|
||||
def get_all_permission_quantity_list():
|
||||
quantity_list = {
|
||||
Enum_Permissions_Crafty.Server_Creation.name: -1,
|
||||
Enum_Permissions_Crafty.User_Config.name: -1,
|
||||
Enum_Permissions_Crafty.Roles_Config.name: -1,
|
||||
EnumPermissionsCrafty.SERVER_CREATION.name: -1,
|
||||
EnumPermissionsCrafty.USER_CONFIG.name: -1,
|
||||
EnumPermissionsCrafty.ROLES_CONFIG.name: -1,
|
||||
}
|
||||
return quantity_list
|
||||
|
||||
@staticmethod
|
||||
def get_permission_quantity_list(user_id):
|
||||
user_crafty = crafty_permissions.get_User_Crafty(user_id)
|
||||
user_crafty = PermissionsCrafty.get_user_crafty(user_id)
|
||||
quantity_list = {
|
||||
Enum_Permissions_Crafty.Server_Creation.name: user_crafty.limit_server_creation, # pylint: disable=line-too-long
|
||||
Enum_Permissions_Crafty.User_Config.name: user_crafty.limit_user_creation,
|
||||
Enum_Permissions_Crafty.Roles_Config.name: user_crafty.limit_role_creation,
|
||||
EnumPermissionsCrafty.SERVER_CREATION.name: user_crafty.limit_server_creation, # pylint: disable=line-too-long
|
||||
EnumPermissionsCrafty.USER_CONFIG.name: user_crafty.limit_user_creation,
|
||||
EnumPermissionsCrafty.ROLES_CONFIG.name: user_crafty.limit_role_creation,
|
||||
}
|
||||
return quantity_list
|
||||
|
||||
@ -122,31 +108,29 @@ class Permissions_Crafty:
|
||||
# User_Crafty Methods
|
||||
# **********************************************************************************
|
||||
@staticmethod
|
||||
def get_User_Crafty(user_id):
|
||||
def get_user_crafty(user_id):
|
||||
try:
|
||||
user_crafty = (
|
||||
User_Crafty.select().where(User_Crafty.user_id == user_id).get()
|
||||
)
|
||||
user_crafty = UserCrafty.select().where(UserCrafty.user_id == user_id).get()
|
||||
except DoesNotExist:
|
||||
user_crafty = User_Crafty.insert(
|
||||
user_crafty = UserCrafty.insert(
|
||||
{
|
||||
User_Crafty.user_id: user_id,
|
||||
User_Crafty.permissions: "000",
|
||||
User_Crafty.limit_server_creation: 0,
|
||||
User_Crafty.limit_user_creation: 0,
|
||||
User_Crafty.limit_role_creation: 0,
|
||||
User_Crafty.created_server: 0,
|
||||
User_Crafty.created_user: 0,
|
||||
User_Crafty.created_role: 0,
|
||||
UserCrafty.user_id: user_id,
|
||||
UserCrafty.permissions: "000",
|
||||
UserCrafty.limit_server_creation: 0,
|
||||
UserCrafty.limit_user_creation: 0,
|
||||
UserCrafty.limit_role_creation: 0,
|
||||
UserCrafty.created_server: 0,
|
||||
UserCrafty.created_user: 0,
|
||||
UserCrafty.created_role: 0,
|
||||
}
|
||||
).execute()
|
||||
user_crafty = crafty_permissions.get_User_Crafty(user_id)
|
||||
user_crafty = PermissionsCrafty.get_user_crafty(user_id)
|
||||
return user_crafty
|
||||
|
||||
@staticmethod
|
||||
def add_user_crafty(user_id, uc_permissions):
|
||||
user_crafty = User_Crafty.insert(
|
||||
{User_Crafty.user_id: user_id, User_Crafty.permissions: uc_permissions}
|
||||
user_crafty = UserCrafty.insert(
|
||||
{UserCrafty.user_id: user_id, UserCrafty.permissions: uc_permissions}
|
||||
).execute()
|
||||
return user_crafty
|
||||
|
||||
@ -159,46 +143,44 @@ class Permissions_Crafty:
|
||||
limit_role_creation,
|
||||
):
|
||||
try:
|
||||
user_crafty = (
|
||||
User_Crafty.select().where(User_Crafty.user_id == user_id).get()
|
||||
)
|
||||
user_crafty = UserCrafty.select().where(UserCrafty.user_id == user_id).get()
|
||||
user_crafty.permissions = permissions_mask
|
||||
user_crafty.limit_server_creation = limit_server_creation
|
||||
user_crafty.limit_user_creation = limit_user_creation
|
||||
user_crafty.limit_role_creation = limit_role_creation
|
||||
User_Crafty.save(user_crafty)
|
||||
UserCrafty.save(user_crafty)
|
||||
except:
|
||||
User_Crafty.insert(
|
||||
UserCrafty.insert(
|
||||
{
|
||||
User_Crafty.user_id: user_id,
|
||||
User_Crafty.permissions: permissions_mask,
|
||||
User_Crafty.limit_server_creation: limit_server_creation,
|
||||
User_Crafty.limit_user_creation: limit_user_creation,
|
||||
User_Crafty.limit_role_creation: limit_role_creation,
|
||||
UserCrafty.user_id: user_id,
|
||||
UserCrafty.permissions: permissions_mask,
|
||||
UserCrafty.limit_server_creation: limit_server_creation,
|
||||
UserCrafty.limit_user_creation: limit_user_creation,
|
||||
UserCrafty.limit_role_creation: limit_role_creation,
|
||||
}
|
||||
).execute()
|
||||
|
||||
@staticmethod
|
||||
def get_created_quantity_list(user_id):
|
||||
user_crafty = crafty_permissions.get_User_Crafty(user_id)
|
||||
user_crafty = PermissionsCrafty.get_user_crafty(user_id)
|
||||
quantity_list = {
|
||||
Enum_Permissions_Crafty.Server_Creation.name: user_crafty.created_server,
|
||||
Enum_Permissions_Crafty.User_Config.name: user_crafty.created_user,
|
||||
Enum_Permissions_Crafty.Roles_Config.name: user_crafty.created_role,
|
||||
EnumPermissionsCrafty.SERVER_CREATION.name: user_crafty.created_server,
|
||||
EnumPermissionsCrafty.USER_CONFIG.name: user_crafty.created_user,
|
||||
EnumPermissionsCrafty.ROLES_CONFIG.name: user_crafty.created_role,
|
||||
}
|
||||
return quantity_list
|
||||
|
||||
@staticmethod
|
||||
def get_crafty_limit_value(user_id, permission):
|
||||
quantity_list = crafty_permissions.get_permission_quantity_list(user_id)
|
||||
quantity_list = PermissionsCrafty.get_permission_quantity_list(user_id)
|
||||
return quantity_list[permission]
|
||||
|
||||
@staticmethod
|
||||
def can_add_in_crafty(user_id, permission):
|
||||
user_crafty = crafty_permissions.get_User_Crafty(user_id)
|
||||
can = crafty_permissions.has_permission(user_crafty.permissions, permission)
|
||||
limit_list = crafty_permissions.get_permission_quantity_list(user_id)
|
||||
quantity_list = crafty_permissions.get_created_quantity_list(user_id)
|
||||
user_crafty = PermissionsCrafty.get_user_crafty(user_id)
|
||||
can = PermissionsCrafty.has_permission(user_crafty.permissions, permission)
|
||||
limit_list = PermissionsCrafty.get_permission_quantity_list(user_id)
|
||||
quantity_list = PermissionsCrafty.get_created_quantity_list(user_id)
|
||||
return can and (
|
||||
(quantity_list[permission.name] < limit_list[permission.name])
|
||||
or limit_list[permission.name] == -1
|
||||
@ -206,26 +188,26 @@ class Permissions_Crafty:
|
||||
|
||||
@staticmethod
|
||||
def add_server_creation(user_id):
|
||||
user_crafty = crafty_permissions.get_User_Crafty(user_id)
|
||||
user_crafty = PermissionsCrafty.get_user_crafty(user_id)
|
||||
user_crafty.created_server += 1
|
||||
User_Crafty.save(user_crafty)
|
||||
UserCrafty.save(user_crafty)
|
||||
return user_crafty.created_server
|
||||
|
||||
@staticmethod
|
||||
def get_api_key_permissions_list(key: ApiKeys):
|
||||
user = key.user
|
||||
if user.superuser and key.superuser:
|
||||
return crafty_permissions.get_permissions_list()
|
||||
user = HelperUsers.get_user(key.user_id)
|
||||
if user["superuser"] and key.superuser:
|
||||
return PermissionsCrafty.get_permissions_list()
|
||||
else:
|
||||
user_permissions_mask = crafty_permissions.get_crafty_permissions_mask(
|
||||
user.user_id
|
||||
)
|
||||
if user["superuser"]:
|
||||
user_permissions_mask = "111"
|
||||
else:
|
||||
user_permissions_mask = PermissionsCrafty.get_crafty_permissions_mask(
|
||||
user["user_id"]
|
||||
)
|
||||
key_permissions_mask: str = key.crafty_permissions
|
||||
permissions_mask = permission_helper.combine_masks(
|
||||
permissions_mask = PermissionHelper.combine_masks(
|
||||
user_permissions_mask, key_permissions_mask
|
||||
)
|
||||
permissions_list = crafty_permissions.get_permissions(permissions_mask)
|
||||
permissions_list = PermissionsCrafty.get_permissions(permissions_mask)
|
||||
return permissions_list
|
||||
|
||||
|
||||
crafty_permissions = Permissions_Crafty()
|
||||
|
@ -1,42 +1,29 @@
|
||||
import logging
|
||||
import datetime
|
||||
from peewee import (
|
||||
ForeignKeyField,
|
||||
CharField,
|
||||
IntegerField,
|
||||
DateTimeField,
|
||||
FloatField,
|
||||
TextField,
|
||||
AutoField,
|
||||
BooleanField,
|
||||
)
|
||||
from playhouse.shortcuts import model_to_dict
|
||||
|
||||
from app.classes.models.users import Users, users_helper
|
||||
from app.classes.models.base_model import BaseModel
|
||||
from app.classes.models.users import Users, HelperUsers
|
||||
from app.classes.models.servers import Servers
|
||||
from app.classes.models.server_permissions import server_permissions
|
||||
from app.classes.shared.helpers import helper
|
||||
from app.classes.shared.main_models import db_helper
|
||||
from app.classes.web.websocket_helper import websocket_helper
|
||||
|
||||
try:
|
||||
from peewee import (
|
||||
SqliteDatabase,
|
||||
Model,
|
||||
ForeignKeyField,
|
||||
CharField,
|
||||
IntegerField,
|
||||
DateTimeField,
|
||||
FloatField,
|
||||
TextField,
|
||||
AutoField,
|
||||
BooleanField,
|
||||
)
|
||||
from playhouse.shortcuts import model_to_dict
|
||||
|
||||
except ModuleNotFoundError as e:
|
||||
helper.auto_installer_fix(e)
|
||||
from app.classes.models.server_permissions import PermissionsServers
|
||||
from app.classes.shared.main_models import DatabaseShortcuts
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
peewee_logger = logging.getLogger("peewee")
|
||||
peewee_logger.setLevel(logging.INFO)
|
||||
database = SqliteDatabase(
|
||||
helper.db_path, pragmas={"journal_mode": "wal", "cache_size": -1024 * 10}
|
||||
)
|
||||
|
||||
# **********************************************************************************
|
||||
# Audit_Log Class
|
||||
# **********************************************************************************
|
||||
class Audit_Log(Model):
|
||||
class AuditLog(BaseModel):
|
||||
audit_id = AutoField()
|
||||
created = DateTimeField(default=datetime.datetime.now)
|
||||
user_name = CharField(default="")
|
||||
@ -48,13 +35,13 @@ class Audit_Log(Model):
|
||||
log_msg = TextField(default="")
|
||||
|
||||
class Meta:
|
||||
database = database
|
||||
table_name = "audit_log"
|
||||
|
||||
|
||||
# **********************************************************************************
|
||||
# Host_Stats Class
|
||||
# **********************************************************************************
|
||||
class Host_Stats(Model):
|
||||
class HostStats(BaseModel):
|
||||
time = DateTimeField(default=datetime.datetime.now, index=True)
|
||||
boot_time = CharField(default="")
|
||||
cpu_usage = FloatField(default=0)
|
||||
@ -68,13 +55,12 @@ class Host_Stats(Model):
|
||||
|
||||
class Meta:
|
||||
table_name = "host_stats"
|
||||
database = database
|
||||
|
||||
|
||||
# **********************************************************************************
|
||||
# Commands Class
|
||||
# **********************************************************************************
|
||||
class Commands(Model):
|
||||
class Commands(BaseModel):
|
||||
command_id = AutoField()
|
||||
created = DateTimeField(default=datetime.datetime.now)
|
||||
server_id = ForeignKeyField(Servers, backref="server", index=True)
|
||||
@ -85,13 +71,12 @@ class Commands(Model):
|
||||
|
||||
class Meta:
|
||||
table_name = "commands"
|
||||
database = database
|
||||
|
||||
|
||||
# **********************************************************************************
|
||||
# Webhooks Class
|
||||
# **********************************************************************************
|
||||
class Webhooks(Model):
|
||||
class Webhooks(BaseModel):
|
||||
id = AutoField()
|
||||
name = CharField(max_length=64, unique=True, index=True)
|
||||
method = CharField(default="POST")
|
||||
@ -101,13 +86,12 @@ class Webhooks(Model):
|
||||
|
||||
class Meta:
|
||||
table_name = "webhooks"
|
||||
database = database
|
||||
|
||||
|
||||
# **********************************************************************************
|
||||
# Schedules Class
|
||||
# **********************************************************************************
|
||||
class Schedules(Model):
|
||||
class Schedules(BaseModel):
|
||||
schedule_id = IntegerField(unique=True, primary_key=True)
|
||||
server_id = ForeignKeyField(Servers, backref="schedule_server")
|
||||
enabled = BooleanField()
|
||||
@ -124,13 +108,12 @@ class Schedules(Model):
|
||||
|
||||
class Meta:
|
||||
table_name = "schedules"
|
||||
database = database
|
||||
|
||||
|
||||
# **********************************************************************************
|
||||
# Backups Class
|
||||
# **********************************************************************************
|
||||
class Backups(Model):
|
||||
class Backups(BaseModel):
|
||||
excluded_dirs = CharField(null=True)
|
||||
max_backups = IntegerField()
|
||||
server_id = ForeignKeyField(Servers, backref="backups_server")
|
||||
@ -138,10 +121,12 @@ class Backups(Model):
|
||||
|
||||
class Meta:
|
||||
table_name = "backups"
|
||||
database = database
|
||||
|
||||
|
||||
class helpers_management:
|
||||
class HelpersManagement:
|
||||
def __init__(self, database, helper):
|
||||
self.database = database
|
||||
self.helper = helper
|
||||
|
||||
# **********************************************************************************
|
||||
# Host_Stats Methods
|
||||
@ -149,7 +134,7 @@ class helpers_management:
|
||||
@staticmethod
|
||||
def get_latest_hosts_stats():
|
||||
# pylint: disable=no-member
|
||||
query = Host_Stats.select().order_by(Host_Stats.id.desc()).get()
|
||||
query = HostStats.select().order_by(HostStats.id.desc()).get()
|
||||
return model_to_dict(query)
|
||||
|
||||
# **********************************************************************************
|
||||
@ -184,62 +169,60 @@ class helpers_management:
|
||||
# **********************************************************************************
|
||||
@staticmethod
|
||||
def get_actity_log():
|
||||
q = Audit_Log.select()
|
||||
return db_helper.return_db_rows(q)
|
||||
query = AuditLog.select()
|
||||
return DatabaseShortcuts.return_db_rows(query)
|
||||
|
||||
@staticmethod
|
||||
def add_to_audit_log(user_id, log_msg, server_id=None, source_ip=None):
|
||||
def add_to_audit_log(self, user_id, log_msg, server_id=None, source_ip=None):
|
||||
logger.debug(f"Adding to audit log User:{user_id} - Message: {log_msg} ")
|
||||
user_data = users_helper.get_user(user_id)
|
||||
user_data = HelperUsers.get_user(user_id)
|
||||
|
||||
audit_msg = f"{str(user_data['username']).capitalize()} {log_msg}"
|
||||
|
||||
server_users = server_permissions.get_server_user_list(server_id)
|
||||
server_users = PermissionsServers.get_server_user_list(server_id)
|
||||
for user in server_users:
|
||||
websocket_helper.broadcast_user(user, "notification", audit_msg)
|
||||
self.helper.websocket_helper.broadcast_user(user, "notification", audit_msg)
|
||||
|
||||
Audit_Log.insert(
|
||||
AuditLog.insert(
|
||||
{
|
||||
Audit_Log.user_name: user_data["username"],
|
||||
Audit_Log.user_id: user_id,
|
||||
Audit_Log.server_id: server_id,
|
||||
Audit_Log.log_msg: audit_msg,
|
||||
Audit_Log.source_ip: source_ip,
|
||||
AuditLog.user_name: user_data["username"],
|
||||
AuditLog.user_id: user_id,
|
||||
AuditLog.server_id: server_id,
|
||||
AuditLog.log_msg: audit_msg,
|
||||
AuditLog.source_ip: source_ip,
|
||||
}
|
||||
).execute()
|
||||
# deletes records when they're more than 100
|
||||
ordered = Audit_Log.select().order_by(+Audit_Log.created)
|
||||
ordered = AuditLog.select().order_by(+AuditLog.created)
|
||||
for item in ordered:
|
||||
if not helper.get_setting("max_audit_entries"):
|
||||
if not self.helper.get_setting("max_audit_entries"):
|
||||
max_entries = 300
|
||||
else:
|
||||
max_entries = helper.get_setting("max_audit_entries")
|
||||
if Audit_Log.select().count() > max_entries:
|
||||
Audit_Log.delete().where(Audit_Log.audit_id == item.audit_id).execute()
|
||||
max_entries = self.helper.get_setting("max_audit_entries")
|
||||
if AuditLog.select().count() > max_entries:
|
||||
AuditLog.delete().where(AuditLog.audit_id == item.audit_id).execute()
|
||||
else:
|
||||
return
|
||||
|
||||
@staticmethod
|
||||
def add_to_audit_log_raw(user_name, user_id, server_id, log_msg, source_ip):
|
||||
Audit_Log.insert(
|
||||
def add_to_audit_log_raw(self, user_name, user_id, server_id, log_msg, source_ip):
|
||||
AuditLog.insert(
|
||||
{
|
||||
Audit_Log.user_name: user_name,
|
||||
Audit_Log.user_id: user_id,
|
||||
Audit_Log.server_id: server_id,
|
||||
Audit_Log.log_msg: log_msg,
|
||||
Audit_Log.source_ip: source_ip,
|
||||
AuditLog.user_name: user_name,
|
||||
AuditLog.user_id: user_id,
|
||||
AuditLog.server_id: server_id,
|
||||
AuditLog.log_msg: log_msg,
|
||||
AuditLog.source_ip: source_ip,
|
||||
}
|
||||
).execute()
|
||||
# deletes records when they're more than 100
|
||||
ordered = Audit_Log.select().order_by(+Audit_Log.created)
|
||||
ordered = AuditLog.select().order_by(+AuditLog.created)
|
||||
for item in ordered:
|
||||
# configurable through app/config/config.json
|
||||
if not helper.get_setting("max_audit_entries"):
|
||||
if not self.helper.get_setting("max_audit_entries"):
|
||||
max_entries = 300
|
||||
else:
|
||||
max_entries = helper.get_setting("max_audit_entries")
|
||||
if Audit_Log.select().count() > max_entries:
|
||||
Audit_Log.delete().where(Audit_Log.audit_id == item.audit_id).execute()
|
||||
max_entries = self.helper.get_setting("max_audit_entries")
|
||||
if AuditLog.select().count() > max_entries:
|
||||
AuditLog.delete().where(AuditLog.audit_id == item.audit_id).execute()
|
||||
else:
|
||||
return
|
||||
|
||||
@ -322,8 +305,11 @@ class helpers_management:
|
||||
|
||||
@staticmethod
|
||||
def get_schedules_enabled():
|
||||
# pylint: disable=singleton-comparison
|
||||
return Schedules.select().where(Schedules.enabled == True).execute()
|
||||
return (
|
||||
Schedules.select()
|
||||
.where(Schedules.enabled == True) # pylint: disable=singleton-comparison
|
||||
.execute()
|
||||
)
|
||||
|
||||
# **********************************************************************************
|
||||
# Backups Methods
|
||||
@ -351,8 +337,8 @@ class helpers_management:
|
||||
}
|
||||
return conf
|
||||
|
||||
@staticmethod
|
||||
def set_backup_config(
|
||||
self,
|
||||
server_id: int,
|
||||
backup_path: str = None,
|
||||
max_backups: int = None,
|
||||
@ -378,21 +364,24 @@ class helpers_management:
|
||||
conf["excluded_dirs"] = dirs_to_exclude
|
||||
conf["compress"] = compress
|
||||
if not new_row:
|
||||
with database.atomic():
|
||||
with self.database.atomic():
|
||||
if backup_path is not None:
|
||||
u1 = (
|
||||
server_rows = (
|
||||
Servers.update(backup_path=backup_path)
|
||||
.where(Servers.server_id == server_id)
|
||||
.execute()
|
||||
)
|
||||
else:
|
||||
u1 = 0
|
||||
u2 = (
|
||||
server_rows = 0
|
||||
backup_rows = (
|
||||
Backups.update(conf).where(Backups.server_id == server_id).execute()
|
||||
)
|
||||
logger.debug(f"Updating existing backup record. {u1}+{u2} rows affected")
|
||||
logger.debug(
|
||||
f"Updating existing backup record. "
|
||||
f"{server_rows}+{backup_rows} rows affected"
|
||||
)
|
||||
else:
|
||||
with database.atomic():
|
||||
with self.database.atomic():
|
||||
conf["server_id"] = server_id
|
||||
if backup_path is not None:
|
||||
Servers.update(backup_path=backup_path).where(
|
||||
@ -401,8 +390,9 @@ class helpers_management:
|
||||
Backups.create(**conf)
|
||||
logger.debug("Creating new backup record.")
|
||||
|
||||
def get_excluded_backup_dirs(self, server_id: int):
|
||||
excluded_dirs = self.get_backup_config(server_id)["excluded_dirs"]
|
||||
@staticmethod
|
||||
def get_excluded_backup_dirs(server_id: int):
|
||||
excluded_dirs = HelpersManagement.get_backup_config(server_id)["excluded_dirs"]
|
||||
if excluded_dirs is not None and excluded_dirs != "":
|
||||
dir_list = excluded_dirs.split(",")
|
||||
else:
|
||||
@ -435,12 +425,6 @@ class helpers_management:
|
||||
|
||||
@staticmethod
|
||||
def clear_unexecuted_commands():
|
||||
Commands.update(
|
||||
{
|
||||
Commands.executed: True
|
||||
# pylint: disable=singleton-comparison
|
||||
}
|
||||
).where(Commands.executed == False).execute()
|
||||
|
||||
|
||||
management_helper = helpers_management()
|
||||
Commands.update({Commands.executed: True}).where(
|
||||
Commands.executed == False # pylint: disable=singleton-comparison
|
||||
).execute()
|
||||
|
@ -1,33 +1,22 @@
|
||||
import logging
|
||||
import datetime
|
||||
from peewee import (
|
||||
CharField,
|
||||
DoesNotExist,
|
||||
AutoField,
|
||||
DateTimeField,
|
||||
)
|
||||
from playhouse.shortcuts import model_to_dict
|
||||
|
||||
from app.classes.shared.helpers import helper
|
||||
|
||||
try:
|
||||
from peewee import (
|
||||
SqliteDatabase,
|
||||
Model,
|
||||
CharField,
|
||||
DoesNotExist,
|
||||
AutoField,
|
||||
DateTimeField,
|
||||
)
|
||||
from playhouse.shortcuts import model_to_dict
|
||||
|
||||
except ModuleNotFoundError as e:
|
||||
helper.auto_installer_fix(e)
|
||||
from app.classes.models.base_model import BaseModel
|
||||
from app.classes.shared.helpers import Helpers
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
peewee_logger = logging.getLogger("peewee")
|
||||
peewee_logger.setLevel(logging.INFO)
|
||||
database = SqliteDatabase(
|
||||
helper.db_path, pragmas={"journal_mode": "wal", "cache_size": -1024 * 10}
|
||||
)
|
||||
|
||||
# **********************************************************************************
|
||||
# Roles Class
|
||||
# **********************************************************************************
|
||||
class Roles(Model):
|
||||
class Roles(BaseModel):
|
||||
role_id = AutoField()
|
||||
created = DateTimeField(default=datetime.datetime.now)
|
||||
last_update = DateTimeField(default=datetime.datetime.now)
|
||||
@ -35,13 +24,15 @@ class Roles(Model):
|
||||
|
||||
class Meta:
|
||||
table_name = "roles"
|
||||
database = database
|
||||
|
||||
|
||||
# **********************************************************************************
|
||||
# Roles Helpers
|
||||
# **********************************************************************************
|
||||
class helper_roles:
|
||||
class HelperRoles:
|
||||
def __init__(self, database):
|
||||
self.database = database
|
||||
|
||||
@staticmethod
|
||||
def get_all_roles():
|
||||
query = Roles.select()
|
||||
@ -63,7 +54,7 @@ class helper_roles:
|
||||
role_id = Roles.insert(
|
||||
{
|
||||
Roles.role_name: role_name.lower(),
|
||||
Roles.created: helper.get_time_as_string(),
|
||||
Roles.created: Helpers.get_time_as_string(),
|
||||
}
|
||||
).execute()
|
||||
return role_id
|
||||
@ -72,17 +63,13 @@ class helper_roles:
|
||||
def update_role(role_id, up_data):
|
||||
return Roles.update(up_data).where(Roles.role_id == role_id).execute()
|
||||
|
||||
@staticmethod
|
||||
def remove_role(role_id):
|
||||
with database.atomic():
|
||||
def remove_role(self, role_id):
|
||||
with self.database.atomic():
|
||||
role = Roles.get(Roles.role_id == role_id)
|
||||
return role.delete_instance()
|
||||
|
||||
@staticmethod
|
||||
def role_id_exists(role_id):
|
||||
if not roles_helper.get_role(role_id):
|
||||
if not HelperRoles.get_role(role_id):
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
roles_helper = helper_roles()
|
||||
|
@ -1,36 +1,24 @@
|
||||
from enum import Enum
|
||||
import logging
|
||||
from peewee import (
|
||||
ForeignKeyField,
|
||||
CharField,
|
||||
CompositeKey,
|
||||
JOIN,
|
||||
)
|
||||
|
||||
from app.classes.models.base_model import BaseModel
|
||||
from app.classes.models.servers import Servers
|
||||
from app.classes.models.roles import Roles
|
||||
from app.classes.models.users import User_Roles, users_helper, ApiKeys, Users
|
||||
from app.classes.shared.helpers import helper
|
||||
from app.classes.shared.permission_helper import permission_helper
|
||||
|
||||
try:
|
||||
from peewee import (
|
||||
SqliteDatabase,
|
||||
Model,
|
||||
ForeignKeyField,
|
||||
CharField,
|
||||
CompositeKey,
|
||||
JOIN,
|
||||
)
|
||||
from enum import Enum
|
||||
|
||||
except ModuleNotFoundError as e:
|
||||
helper.auto_installer_fix(e)
|
||||
from app.classes.models.users import UserRoles, HelperUsers, ApiKeys, Users
|
||||
from app.classes.shared.permission_helper import PermissionHelper
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
peewee_logger = logging.getLogger("peewee")
|
||||
peewee_logger.setLevel(logging.INFO)
|
||||
database = SqliteDatabase(
|
||||
helper.db_path, pragmas={"journal_mode": "wal", "cache_size": -1024 * 10}
|
||||
)
|
||||
|
||||
# **********************************************************************************
|
||||
# Role Servers Class
|
||||
# **********************************************************************************
|
||||
class Role_Servers(Model):
|
||||
class RoleServers(BaseModel):
|
||||
role_id = ForeignKeyField(Roles, backref="role_server")
|
||||
server_id = ForeignKeyField(Servers, backref="role_server")
|
||||
permissions = CharField(default="00000000")
|
||||
@ -38,52 +26,51 @@ class Role_Servers(Model):
|
||||
class Meta:
|
||||
table_name = "role_servers"
|
||||
primary_key = CompositeKey("role_id", "server_id")
|
||||
database = database
|
||||
|
||||
|
||||
# **********************************************************************************
|
||||
# Servers Permissions Class
|
||||
# **********************************************************************************
|
||||
class Enum_Permissions_Server(Enum):
|
||||
Commands = 0
|
||||
Terminal = 1
|
||||
Logs = 2
|
||||
Schedule = 3
|
||||
Backup = 4
|
||||
Files = 5
|
||||
Config = 6
|
||||
Players = 7
|
||||
class EnumPermissionsServer(Enum):
|
||||
COMMANDS = 0
|
||||
TERMINAL = 1
|
||||
LOGS = 2
|
||||
SCHEDULE = 3
|
||||
BACKUP = 4
|
||||
FILES = 5
|
||||
CONFIG = 6
|
||||
PLAYERS = 7
|
||||
|
||||
|
||||
class Permissions_Servers:
|
||||
class PermissionsServers:
|
||||
@staticmethod
|
||||
def get_or_create(role_id, server, permissions_mask):
|
||||
return Role_Servers.get_or_create(
|
||||
return RoleServers.get_or_create(
|
||||
role_id=role_id, server_id=server, permissions=permissions_mask
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def get_permissions_list():
|
||||
permissions_list = []
|
||||
for member in Enum_Permissions_Server.__members__.items():
|
||||
for member in EnumPermissionsServer.__members__.items():
|
||||
permissions_list.append(member[1])
|
||||
return permissions_list
|
||||
|
||||
@staticmethod
|
||||
def get_permissions(permissions_mask):
|
||||
permissions_list = []
|
||||
for member in Enum_Permissions_Server.__members__.items():
|
||||
if server_permissions.has_permission(permissions_mask, member[1]):
|
||||
for member in EnumPermissionsServer.__members__.items():
|
||||
if PermissionsServers.has_permission(permissions_mask, member[1]):
|
||||
permissions_list.append(member[1])
|
||||
return permissions_list
|
||||
|
||||
@staticmethod
|
||||
def has_permission(permission_mask, permission_tested: Enum_Permissions_Server):
|
||||
def has_permission(permission_mask, permission_tested: EnumPermissionsServer):
|
||||
return permission_mask[permission_tested.value] == "1"
|
||||
|
||||
@staticmethod
|
||||
def set_permission(
|
||||
permission_mask, permission_tested: Enum_Permissions_Server, value
|
||||
permission_mask, permission_tested: EnumPermissionsServer, value
|
||||
):
|
||||
list_perms = list(permission_mask)
|
||||
list_perms[permission_tested.value] = str(value)
|
||||
@ -91,14 +78,14 @@ class Permissions_Servers:
|
||||
return permission_mask
|
||||
|
||||
@staticmethod
|
||||
def get_permission(permission_mask, permission_tested: Enum_Permissions_Server):
|
||||
def get_permission(permission_mask, permission_tested: EnumPermissionsServer):
|
||||
return permission_mask[permission_tested.value]
|
||||
|
||||
@staticmethod
|
||||
def get_token_permissions(permissions_mask, api_permissions_mask):
|
||||
permissions_list = []
|
||||
for member in Enum_Permissions_Server.__members__.items():
|
||||
if permission_helper.both_have_perm(
|
||||
for member in EnumPermissionsServer.__members__.items():
|
||||
if PermissionHelper.both_have_perm(
|
||||
permissions_mask, api_permissions_mask, member[1]
|
||||
):
|
||||
permissions_list.append(member[1])
|
||||
@ -109,31 +96,31 @@ class Permissions_Servers:
|
||||
# **********************************************************************************
|
||||
@staticmethod
|
||||
def get_role_servers_from_role_id(roleid):
|
||||
return Role_Servers.select().where(Role_Servers.role_id == roleid)
|
||||
return RoleServers.select().where(RoleServers.role_id == roleid)
|
||||
|
||||
@staticmethod
|
||||
def get_servers_from_role(role_id):
|
||||
return (
|
||||
Role_Servers.select()
|
||||
RoleServers.select()
|
||||
.join(Servers, JOIN.INNER)
|
||||
.where(Role_Servers.role_id == role_id)
|
||||
.where(RoleServers.role_id == role_id)
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def get_roles_from_server(server_id):
|
||||
return (
|
||||
Role_Servers.select()
|
||||
RoleServers.select()
|
||||
.join(Roles, JOIN.INNER)
|
||||
.where(Role_Servers.server_id == server_id)
|
||||
.where(RoleServers.server_id == server_id)
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def add_role_server(server_id, role_id, rs_permissions="00000000"):
|
||||
servers = Role_Servers.insert(
|
||||
servers = RoleServers.insert(
|
||||
{
|
||||
Role_Servers.server_id: server_id,
|
||||
Role_Servers.role_id: role_id,
|
||||
Role_Servers.permissions: rs_permissions,
|
||||
RoleServers.server_id: server_id,
|
||||
RoleServers.role_id: role_id,
|
||||
RoleServers.permissions: rs_permissions,
|
||||
}
|
||||
).execute()
|
||||
return servers
|
||||
@ -142,9 +129,9 @@ class Permissions_Servers:
|
||||
def get_permissions_mask(role_id, server_id):
|
||||
permissions_mask = ""
|
||||
role_server = (
|
||||
Role_Servers.select()
|
||||
.where(Role_Servers.role_id == role_id)
|
||||
.where(Role_Servers.server_id == server_id)
|
||||
RoleServers.select()
|
||||
.where(RoleServers.role_id == role_id)
|
||||
.where(RoleServers.server_id == server_id)
|
||||
.get()
|
||||
)
|
||||
permissions_mask = role_server.permissions
|
||||
@ -153,9 +140,7 @@ class Permissions_Servers:
|
||||
@staticmethod
|
||||
def get_server_roles(server_id):
|
||||
role_list = []
|
||||
roles = (
|
||||
Role_Servers.select().where(Role_Servers.server_id == server_id).execute()
|
||||
)
|
||||
roles = RoleServers.select().where(RoleServers.server_id == server_id).execute()
|
||||
for role in roles:
|
||||
role_list.append(role.role_id)
|
||||
return role_list
|
||||
@ -163,74 +148,70 @@ class Permissions_Servers:
|
||||
@staticmethod
|
||||
def get_role_permissions_list(role_id):
|
||||
permissions_mask = "00000000"
|
||||
role_server = Role_Servers.get_or_none(Role_Servers.role_id == role_id)
|
||||
role_server = RoleServers.get_or_none(RoleServers.role_id == role_id)
|
||||
if role_server is not None:
|
||||
permissions_mask = role_server.permissions
|
||||
permissions_list = server_permissions.get_permissions(permissions_mask)
|
||||
permissions_list = PermissionsServers.get_permissions(permissions_mask)
|
||||
return permissions_list
|
||||
|
||||
@staticmethod
|
||||
def update_role_permission(role_id, server_id, permissions_mask):
|
||||
role_server = (
|
||||
Role_Servers.select()
|
||||
.where(Role_Servers.role_id == role_id)
|
||||
.where(Role_Servers.server_id == server_id)
|
||||
RoleServers.select()
|
||||
.where(RoleServers.role_id == role_id)
|
||||
.where(RoleServers.server_id == server_id)
|
||||
.get()
|
||||
)
|
||||
role_server.permissions = permissions_mask
|
||||
Role_Servers.save(role_server)
|
||||
RoleServers.save(role_server)
|
||||
|
||||
@staticmethod
|
||||
def delete_roles_permissions(role_id, removed_servers=None):
|
||||
if removed_servers is None:
|
||||
removed_servers = {}
|
||||
return (
|
||||
Role_Servers.delete()
|
||||
.where(Role_Servers.role_id == role_id)
|
||||
.where(Role_Servers.server_id.in_(removed_servers))
|
||||
RoleServers.delete()
|
||||
.where(RoleServers.role_id == role_id)
|
||||
.where(RoleServers.server_id.in_(removed_servers))
|
||||
.execute()
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def remove_roles_of_server(server_id):
|
||||
with database.atomic():
|
||||
return (
|
||||
Role_Servers.delete()
|
||||
.where(Role_Servers.server_id == server_id)
|
||||
.execute()
|
||||
)
|
||||
return RoleServers.delete().where(RoleServers.server_id == server_id).execute()
|
||||
|
||||
@staticmethod
|
||||
def get_user_id_permissions_mask(user_id, server_id: str):
|
||||
user = users_helper.get_user_model(user_id)
|
||||
return server_permissions.get_user_permissions_mask(user, server_id)
|
||||
user = HelperUsers.get_user_model(user_id)
|
||||
return PermissionsServers.get_user_permissions_mask(user, server_id)
|
||||
|
||||
@staticmethod
|
||||
def get_user_permissions_mask(user: Users, server_id: str):
|
||||
if user.superuser:
|
||||
permissions_mask = "1" * len(server_permissions.get_permissions_list())
|
||||
permissions_mask = "1" * len(PermissionsServers.get_permissions_list())
|
||||
else:
|
||||
roles_list = users_helper.get_user_roles_id(user.user_id)
|
||||
roles_list = HelperUsers.get_user_roles_id(user.user_id)
|
||||
role_server = (
|
||||
Role_Servers.select()
|
||||
.where(Role_Servers.role_id.in_(roles_list))
|
||||
.where(Role_Servers.server_id == server_id)
|
||||
RoleServers.select()
|
||||
.where(RoleServers.role_id.in_(roles_list))
|
||||
.where(RoleServers.server_id == server_id)
|
||||
.execute()
|
||||
)
|
||||
try:
|
||||
permissions_mask = role_server[0].permissions
|
||||
except IndexError:
|
||||
permissions_mask = "0" * len(server_permissions.get_permissions_list())
|
||||
permissions_mask = "0" * len(PermissionsServers.get_permissions_list())
|
||||
return permissions_mask
|
||||
|
||||
@staticmethod
|
||||
def get_server_user_list(server_id):
|
||||
final_users = []
|
||||
server_roles = Role_Servers.select().where(Role_Servers.server_id == server_id)
|
||||
# pylint: disable=singleton-comparison
|
||||
super_users = Users.select().where(Users.superuser == True)
|
||||
server_roles = RoleServers.select().where(RoleServers.server_id == server_id)
|
||||
super_users = Users.select().where(
|
||||
Users.superuser == True # pylint: disable=singleton-comparison
|
||||
)
|
||||
for role in server_roles:
|
||||
users = User_Roles.select().where(User_Roles.role_id == role.role_id)
|
||||
users = UserRoles.select().where(UserRoles.role_id == role.role_id)
|
||||
for user in users:
|
||||
if user.user_id.user_id not in final_users:
|
||||
final_users.append(user.user_id.user_id)
|
||||
@ -241,45 +222,48 @@ class Permissions_Servers:
|
||||
|
||||
@staticmethod
|
||||
def get_user_id_permissions_list(user_id, server_id: str):
|
||||
user = users_helper.get_user_model(user_id)
|
||||
return server_permissions.get_user_permissions_list(user, server_id)
|
||||
user = HelperUsers.get_user_model(user_id)
|
||||
return PermissionsServers.get_user_permissions_list(user, server_id)
|
||||
|
||||
@staticmethod
|
||||
def get_user_permissions_list(user: Users, server_id: str):
|
||||
if user.superuser:
|
||||
permissions_list = server_permissions.get_permissions_list()
|
||||
permissions_list = PermissionsServers.get_permissions_list()
|
||||
else:
|
||||
permissions_mask = server_permissions.get_user_permissions_mask(
|
||||
permissions_mask = PermissionsServers.get_user_permissions_mask(
|
||||
user, server_id
|
||||
)
|
||||
permissions_list = server_permissions.get_permissions(permissions_mask)
|
||||
permissions_list = PermissionsServers.get_permissions(permissions_mask)
|
||||
return permissions_list
|
||||
|
||||
@staticmethod
|
||||
def get_api_key_id_permissions_list(key_id, server_id: str):
|
||||
key = ApiKeys.get(ApiKeys.token_id == key_id)
|
||||
return server_permissions.get_api_key_permissions_list(key, server_id)
|
||||
return PermissionsServers.get_api_key_permissions_list(key, server_id)
|
||||
|
||||
@staticmethod
|
||||
def get_api_key_permissions_list(key: ApiKeys, server_id: str):
|
||||
user = key.user
|
||||
if user.superuser and key.superuser:
|
||||
return server_permissions.get_permissions_list()
|
||||
user = HelperUsers.get_user(key.user_id)
|
||||
if user["superuser"] and key.superuser:
|
||||
return PermissionsServers.get_permissions_list()
|
||||
else:
|
||||
roles_list = users_helper.get_user_roles_id(user["user_id"])
|
||||
roles_list = HelperUsers.get_user_roles_id(user["user_id"])
|
||||
role_server = (
|
||||
Role_Servers.select()
|
||||
.where(Role_Servers.role_id.in_(roles_list))
|
||||
.where(Role_Servers.server_id == server_id)
|
||||
RoleServers.select()
|
||||
.where(RoleServers.role_id.in_(roles_list))
|
||||
.where(RoleServers.server_id == server_id)
|
||||
.execute()
|
||||
)
|
||||
user_permissions_mask = role_server[0].permissions
|
||||
try:
|
||||
user_permissions_mask = role_server[0].permissions
|
||||
except:
|
||||
if user["superuser"]:
|
||||
user_permissions_mask = "11111111"
|
||||
else:
|
||||
user_permissions_mask = "00000000"
|
||||
key_permissions_mask = key.server_permissions
|
||||
permissions_mask = permission_helper.combine_masks(
|
||||
permissions_mask = PermissionHelper.combine_masks(
|
||||
user_permissions_mask, key_permissions_mask
|
||||
)
|
||||
permissions_list = server_permissions.get_permissions(permissions_mask)
|
||||
permissions_list = PermissionsServers.get_permissions(permissions_mask)
|
||||
return permissions_list
|
||||
|
||||
|
||||
server_permissions = Permissions_Servers()
|
||||
|
355
app/classes/models/server_stats.py
Normal file
355
app/classes/models/server_stats.py
Normal file
@ -0,0 +1,355 @@
|
||||
import os
|
||||
import logging
|
||||
import datetime
|
||||
|
||||
from app.classes.models.servers import Servers, HelperServers
|
||||
from app.classes.shared.helpers import Helpers
|
||||
from app.classes.shared.main_models import DatabaseShortcuts
|
||||
from app.classes.shared.migration import MigrationManager
|
||||
|
||||
try:
|
||||
from peewee import (
|
||||
SqliteDatabase,
|
||||
Model,
|
||||
DatabaseProxy,
|
||||
ForeignKeyField,
|
||||
CharField,
|
||||
AutoField,
|
||||
DateTimeField,
|
||||
BooleanField,
|
||||
IntegerField,
|
||||
FloatField,
|
||||
)
|
||||
|
||||
except ModuleNotFoundError as e:
|
||||
Helpers.auto_installer_fix(e)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
peewee_logger = logging.getLogger("peewee")
|
||||
peewee_logger.setLevel(logging.INFO)
|
||||
database_stats_proxy = DatabaseProxy()
|
||||
|
||||
|
||||
# **********************************************************************************
|
||||
# Servers Stats Class
|
||||
# **********************************************************************************
|
||||
class ServerStats(Model):
|
||||
stats_id = AutoField()
|
||||
created = DateTimeField(default=datetime.datetime.now)
|
||||
server_id = ForeignKeyField(Servers, backref="server", index=True)
|
||||
started = CharField(default="")
|
||||
running = BooleanField(default=False)
|
||||
cpu = FloatField(default=0)
|
||||
mem = FloatField(default=0)
|
||||
mem_percent = FloatField(default=0)
|
||||
world_name = CharField(default="")
|
||||
world_size = CharField(default="")
|
||||
server_port = IntegerField(default=25565)
|
||||
int_ping_results = CharField(default="")
|
||||
online = IntegerField(default=0)
|
||||
max = IntegerField(default=0)
|
||||
players = CharField(default="")
|
||||
desc = CharField(default="Unable to Connect")
|
||||
version = CharField(default="")
|
||||
updating = BooleanField(default=False)
|
||||
waiting_start = BooleanField(default=False)
|
||||
first_run = BooleanField(default=True)
|
||||
crashed = BooleanField(default=False)
|
||||
downloading = BooleanField(default=False)
|
||||
|
||||
class Meta:
|
||||
table_name = "server_stats"
|
||||
database = database_stats_proxy
|
||||
|
||||
|
||||
# **********************************************************************************
|
||||
# Servers_Stats Methods
|
||||
# **********************************************************************************
|
||||
class HelperServerStats:
|
||||
def __init__(self, database):
|
||||
self.database = database
|
||||
|
||||
@staticmethod
|
||||
def init_database(server_id):
|
||||
try:
|
||||
server = HelperServers.get_server_data_by_id(server_id)
|
||||
db_folder = os.path.join(f"{server['path']}", "db_stats")
|
||||
db_file = os.path.join(
|
||||
db_folder,
|
||||
f"{server['server_name']}" + ".sqlite",
|
||||
)
|
||||
database = SqliteDatabase(
|
||||
db_file, pragmas={"journal_mode": "wal", "cache_size": -1024 * 10}
|
||||
)
|
||||
if not os.path.exists(db_file):
|
||||
try:
|
||||
os.mkdir(db_folder)
|
||||
except Exception as ex:
|
||||
logger.warning(
|
||||
f"Error try to create the db_stats folder for server : {ex}"
|
||||
)
|
||||
helper_stats = Helpers()
|
||||
helper_stats.migration_dir = os.path.join(
|
||||
f"{helper_stats.migration_dir}", "stats"
|
||||
)
|
||||
helper_stats.db_path = db_file
|
||||
database_stats_proxy.initialize(database)
|
||||
migration_manager = MigrationManager(database, helper_stats)
|
||||
migration_manager.up() # Automatically runs migrations
|
||||
database_stats_proxy.initialize(database)
|
||||
except Exception as ex:
|
||||
logger.warning(
|
||||
f"Error try to look for the db_stats files for server : {ex}"
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def select_database(server_id):
|
||||
try:
|
||||
server = HelperServers.get_server_data_by_id(server_id)
|
||||
db_file = os.path.join(
|
||||
f"{server['path']}",
|
||||
"db_stats",
|
||||
f"{server['server_name']}" + ".sqlite",
|
||||
)
|
||||
database = SqliteDatabase(
|
||||
db_file, pragmas={"journal_mode": "wal", "cache_size": -1024 * 10}
|
||||
)
|
||||
database_stats_proxy.initialize(database)
|
||||
except Exception as ex:
|
||||
logger.warning(
|
||||
f"Error try to look for the db_stats files for server : {ex}"
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def get_all_servers_stats():
|
||||
servers = HelperServers.get_all_defined_servers()
|
||||
server_data = []
|
||||
try:
|
||||
for s in servers:
|
||||
HelperServerStats.select_database(s.get("server_id"))
|
||||
latest = (
|
||||
ServerStats.select()
|
||||
.where(ServerStats.server_id == s.get("server_id"))
|
||||
.order_by(ServerStats.created.desc())
|
||||
.limit(1)
|
||||
)
|
||||
server_data.append(
|
||||
{
|
||||
"server_data": s,
|
||||
"stats": DatabaseShortcuts.return_rows(latest)[0],
|
||||
"user_command_permission": True,
|
||||
}
|
||||
)
|
||||
except IndexError as ex:
|
||||
logger.error(
|
||||
f"Stats collection failed with error: {ex}. Was a server just created?"
|
||||
)
|
||||
return server_data
|
||||
|
||||
@staticmethod
|
||||
def insert_server_stats(server):
|
||||
server_id = server.get("id", 0)
|
||||
HelperServerStats.select_database(server_id)
|
||||
|
||||
if server_id == 0:
|
||||
logger.warning("Stats saving failed with error: Server unknown (id = 0)")
|
||||
return
|
||||
|
||||
ServerStats.insert(
|
||||
{
|
||||
ServerStats.server_id: server.get("id", 0),
|
||||
ServerStats.started: server.get("started", ""),
|
||||
ServerStats.running: server.get("running", False),
|
||||
ServerStats.cpu: server.get("cpu", 0),
|
||||
ServerStats.mem: server.get("mem", 0),
|
||||
ServerStats.mem_percent: server.get("mem_percent", 0),
|
||||
ServerStats.world_name: server.get("world_name", ""),
|
||||
ServerStats.world_size: server.get("world_size", ""),
|
||||
ServerStats.server_port: server.get("server_port", ""),
|
||||
ServerStats.int_ping_results: server.get("int_ping_results", False),
|
||||
ServerStats.online: server.get("online", False),
|
||||
ServerStats.max: server.get("max", False),
|
||||
ServerStats.players: server.get("players", False),
|
||||
ServerStats.desc: server.get("desc", False),
|
||||
ServerStats.version: server.get("version", False),
|
||||
}
|
||||
).execute()
|
||||
|
||||
@staticmethod
|
||||
def remove_old_stats(server_id, last_week):
|
||||
HelperServerStats.select_database(server_id)
|
||||
ServerStats.delete().where(ServerStats.created < last_week).execute()
|
||||
|
||||
@staticmethod
|
||||
def get_latest_server_stats(server_id):
|
||||
HelperServerStats.select_database(server_id)
|
||||
return (
|
||||
ServerStats.select()
|
||||
.where(ServerStats.server_id == server_id)
|
||||
.order_by(ServerStats.created.desc())
|
||||
.limit(1)
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def get_server_stats_by_id(server_id):
|
||||
HelperServerStats.select_database(server_id)
|
||||
stats = (
|
||||
ServerStats.select()
|
||||
.where(ServerStats.server_id == server_id)
|
||||
.order_by(ServerStats.created.desc())
|
||||
.limit(1)
|
||||
)
|
||||
return DatabaseShortcuts.return_rows(stats)[0]
|
||||
|
||||
@staticmethod
|
||||
def server_id_exists(server_id):
|
||||
HelperServerStats.select_database(server_id)
|
||||
if not HelperServers.get_server_data_by_id(server_id):
|
||||
return False
|
||||
return True
|
||||
|
||||
@staticmethod
|
||||
def sever_crashed(server_id):
|
||||
HelperServerStats.select_database(server_id)
|
||||
with database_stats_proxy.atomic():
|
||||
ServerStats.update(crashed=True).where(
|
||||
ServerStats.server_id == server_id
|
||||
).execute()
|
||||
|
||||
@staticmethod
|
||||
def set_download(server_id):
|
||||
HelperServerStats.select_database(server_id)
|
||||
with database_stats_proxy.atomic():
|
||||
ServerStats.update(downloading=True).where(
|
||||
ServerStats.server_id == server_id
|
||||
).execute()
|
||||
|
||||
@staticmethod
|
||||
def finish_download(server_id):
|
||||
HelperServerStats.select_database(server_id)
|
||||
with database_stats_proxy.atomic():
|
||||
ServerStats.update(downloading=False).where(
|
||||
ServerStats.server_id == server_id
|
||||
).execute()
|
||||
|
||||
@staticmethod
|
||||
def get_download_status(server_id):
|
||||
HelperServerStats.select_database(server_id)
|
||||
download_status = (
|
||||
ServerStats.select().where(ServerStats.server_id == server_id).get()
|
||||
)
|
||||
return download_status.downloading
|
||||
|
||||
@staticmethod
|
||||
def server_crash_reset(server_id):
|
||||
if server_id is None:
|
||||
return
|
||||
|
||||
HelperServerStats.select_database(server_id)
|
||||
with database_stats_proxy.atomic():
|
||||
ServerStats.update(crashed=False).where(
|
||||
ServerStats.server_id == server_id
|
||||
).execute()
|
||||
|
||||
@staticmethod
|
||||
def is_crashed(server_id):
|
||||
HelperServerStats.select_database(server_id)
|
||||
svr = ServerStats.select().where(ServerStats.server_id == server_id).get()
|
||||
# pylint: disable=singleton-comparison
|
||||
if svr.crashed == True:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def set_update(server_id, value):
|
||||
if server_id is None:
|
||||
return
|
||||
|
||||
HelperServerStats.select_database(server_id)
|
||||
try:
|
||||
# Checks if server even exists
|
||||
ServerStats.select().where(ServerStats.server_id == server_id)
|
||||
except Exception as ex:
|
||||
logger.error(f"Database entry not found! {ex}")
|
||||
with database_stats_proxy.atomic():
|
||||
ServerStats.update(updating=value).where(
|
||||
ServerStats.server_id == server_id
|
||||
).execute()
|
||||
|
||||
@staticmethod
|
||||
def get_update_status(server_id):
|
||||
HelperServerStats.select_database(server_id)
|
||||
update_status = (
|
||||
ServerStats.select().where(ServerStats.server_id == server_id).get()
|
||||
)
|
||||
return update_status.updating
|
||||
|
||||
@staticmethod
|
||||
def set_first_run(server_id):
|
||||
HelperServerStats.select_database(server_id)
|
||||
# Sets first run to false
|
||||
try:
|
||||
# Checks if server even exists
|
||||
ServerStats.select().where(ServerStats.server_id == server_id)
|
||||
except Exception as ex:
|
||||
logger.error(f"Database entry not found! {ex}")
|
||||
return
|
||||
with database_stats_proxy.atomic():
|
||||
ServerStats.update(first_run=False).where(
|
||||
ServerStats.server_id == server_id
|
||||
).execute()
|
||||
|
||||
@staticmethod
|
||||
def get_first_run(server_id):
|
||||
HelperServerStats.select_database(server_id)
|
||||
first_run = ServerStats.select().where(ServerStats.server_id == server_id).get()
|
||||
return first_run.first_run
|
||||
|
||||
@staticmethod
|
||||
def get_ttl_without_player(server_id):
|
||||
HelperServerStats.select_database(server_id)
|
||||
last_stat = (
|
||||
ServerStats.select()
|
||||
.where(ServerStats.server_id == server_id)
|
||||
.order_by(ServerStats.created.desc())
|
||||
.first()
|
||||
)
|
||||
last_stat_with_player = (
|
||||
ServerStats.select()
|
||||
.where(ServerStats.server_id == server_id)
|
||||
.where(ServerStats.online > 0)
|
||||
.order_by(ServerStats.created.desc())
|
||||
.first()
|
||||
)
|
||||
return last_stat.created - last_stat_with_player.created
|
||||
|
||||
@staticmethod
|
||||
def can_stop_no_players(server_id, time_limit):
|
||||
HelperServerStats.select_database(server_id)
|
||||
can = False
|
||||
ttl_no_players = HelperServerStats.get_ttl_without_player(server_id)
|
||||
if (time_limit == -1) or (ttl_no_players > time_limit):
|
||||
can = True
|
||||
return can
|
||||
|
||||
@staticmethod
|
||||
def set_waiting_start(server_id, value):
|
||||
HelperServerStats.select_database(server_id)
|
||||
try:
|
||||
# Checks if server even exists
|
||||
ServerStats.select().where(ServerStats.server_id == server_id)
|
||||
except Exception as ex:
|
||||
logger.error(f"Database entry not found! {ex}")
|
||||
with database_stats_proxy.atomic():
|
||||
ServerStats.update(waiting_start=value).where(
|
||||
ServerStats.server_id == server_id
|
||||
).execute()
|
||||
|
||||
@staticmethod
|
||||
def get_waiting_start(server_id):
|
||||
HelperServerStats.select_database(server_id)
|
||||
waiting_start = (
|
||||
ServerStats.select().where(ServerStats.server_id == server_id).get()
|
||||
)
|
||||
return waiting_start.waiting_start
|
@ -1,36 +1,22 @@
|
||||
import logging
|
||||
import datetime
|
||||
from peewee import (
|
||||
CharField,
|
||||
AutoField,
|
||||
DateTimeField,
|
||||
BooleanField,
|
||||
IntegerField,
|
||||
)
|
||||
|
||||
from app.classes.shared.helpers import helper
|
||||
from app.classes.shared.main_models import db_helper
|
||||
|
||||
try:
|
||||
from peewee import (
|
||||
SqliteDatabase,
|
||||
Model,
|
||||
ForeignKeyField,
|
||||
CharField,
|
||||
AutoField,
|
||||
DateTimeField,
|
||||
BooleanField,
|
||||
IntegerField,
|
||||
FloatField,
|
||||
)
|
||||
|
||||
except ModuleNotFoundError as e:
|
||||
helper.auto_installer_fix(e)
|
||||
from app.classes.shared.main_models import DatabaseShortcuts
|
||||
from app.classes.models.base_model import BaseModel
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
peewee_logger = logging.getLogger("peewee")
|
||||
peewee_logger.setLevel(logging.INFO)
|
||||
database = SqliteDatabase(
|
||||
helper.db_path, pragmas={"journal_mode": "wal", "cache_size": -1024 * 10}
|
||||
)
|
||||
|
||||
# **********************************************************************************
|
||||
# Servers Class
|
||||
# **********************************************************************************
|
||||
class Servers(Model):
|
||||
class Servers(BaseModel):
|
||||
server_id = AutoField()
|
||||
created = DateTimeField(default=datetime.datetime.now)
|
||||
server_uuid = CharField(default="", index=True)
|
||||
@ -52,45 +38,14 @@ class Servers(Model):
|
||||
|
||||
class Meta:
|
||||
table_name = "servers"
|
||||
database = database
|
||||
|
||||
|
||||
# **********************************************************************************
|
||||
# Servers Stats Class
|
||||
# **********************************************************************************
|
||||
class Server_Stats(Model):
|
||||
stats_id = AutoField()
|
||||
created = DateTimeField(default=datetime.datetime.now)
|
||||
server_id = ForeignKeyField(Servers, backref="server", index=True)
|
||||
started = CharField(default="")
|
||||
running = BooleanField(default=False)
|
||||
cpu = FloatField(default=0)
|
||||
mem = FloatField(default=0)
|
||||
mem_percent = FloatField(default=0)
|
||||
world_name = CharField(default="")
|
||||
world_size = CharField(default="")
|
||||
server_port = IntegerField(default=25565)
|
||||
int_ping_results = CharField(default="")
|
||||
online = IntegerField(default=0)
|
||||
max = IntegerField(default=0)
|
||||
players = CharField(default="")
|
||||
desc = CharField(default="Unable to Connect")
|
||||
version = CharField(default="")
|
||||
updating = BooleanField(default=False)
|
||||
waiting_start = BooleanField(default=False)
|
||||
first_run = BooleanField(default=True)
|
||||
crashed = BooleanField(default=False)
|
||||
downloading = BooleanField(default=False)
|
||||
|
||||
class Meta:
|
||||
table_name = "server_stats"
|
||||
database = database
|
||||
|
||||
|
||||
# **********************************************************************************
|
||||
# Servers Class
|
||||
# **********************************************************************************
|
||||
class helper_servers:
|
||||
class HelperServers:
|
||||
def __init__(self, database):
|
||||
self.database = database
|
||||
|
||||
# **********************************************************************************
|
||||
# Generic Servers Methods
|
||||
@ -139,16 +94,15 @@ class helper_servers:
|
||||
def update_server(server_obj):
|
||||
return server_obj.save()
|
||||
|
||||
@staticmethod
|
||||
def remove_server(server_id):
|
||||
with database.atomic():
|
||||
def remove_server(self, server_id):
|
||||
with self.database.atomic():
|
||||
Servers.delete().where(Servers.server_id == server_id).execute()
|
||||
|
||||
@staticmethod
|
||||
def get_server_data_by_id(server_id):
|
||||
query = Servers.select().where(Servers.server_id == server_id).limit(1)
|
||||
try:
|
||||
return db_helper.return_rows(query)[0]
|
||||
return DatabaseShortcuts.return_rows(query)[0]
|
||||
except IndexError:
|
||||
return {}
|
||||
|
||||
@ -158,197 +112,13 @@ class helper_servers:
|
||||
@staticmethod
|
||||
def get_all_defined_servers():
|
||||
query = Servers.select()
|
||||
return db_helper.return_rows(query)
|
||||
|
||||
@staticmethod
|
||||
def get_all_servers_stats():
|
||||
servers = servers_helper.get_all_defined_servers()
|
||||
server_data = []
|
||||
try:
|
||||
for s in servers:
|
||||
latest = (
|
||||
Server_Stats.select()
|
||||
.where(Server_Stats.server_id == s.get("server_id"))
|
||||
.order_by(Server_Stats.created.desc())
|
||||
.limit(1)
|
||||
)
|
||||
server_data.append(
|
||||
{
|
||||
"server_data": s,
|
||||
"stats": db_helper.return_rows(latest)[0],
|
||||
"user_command_permission": True,
|
||||
}
|
||||
)
|
||||
except IndexError as ex:
|
||||
logger.error(
|
||||
f"Stats collection failed with error: {ex}. Was a server just created?"
|
||||
)
|
||||
return server_data
|
||||
return DatabaseShortcuts.return_rows(query)
|
||||
|
||||
@staticmethod
|
||||
def get_server_friendly_name(server_id):
|
||||
server_data = servers_helper.get_server_data_by_id(server_id)
|
||||
server_data = HelperServers.get_server_data_by_id(server_id)
|
||||
friendly_name = (
|
||||
f"{server_data.get('server_name', None)} "
|
||||
f"with ID: {server_data.get('server_id', 0)}"
|
||||
)
|
||||
return friendly_name
|
||||
|
||||
# **********************************************************************************
|
||||
# Servers_Stats Methods
|
||||
# **********************************************************************************
|
||||
@staticmethod
|
||||
def get_latest_server_stats(server_id):
|
||||
return (
|
||||
Server_Stats.select()
|
||||
.where(Server_Stats.server_id == server_id)
|
||||
.order_by(Server_Stats.created.desc())
|
||||
.limit(1)
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def get_server_stats_by_id(server_id):
|
||||
stats = (
|
||||
Server_Stats.select()
|
||||
.where(Server_Stats.server_id == server_id)
|
||||
.order_by(Server_Stats.created.desc())
|
||||
.limit(1)
|
||||
)
|
||||
return db_helper.return_rows(stats)[0]
|
||||
|
||||
@staticmethod
|
||||
def server_id_exists(server_id):
|
||||
if not servers_helper.get_server_data_by_id(server_id):
|
||||
return False
|
||||
return True
|
||||
|
||||
@staticmethod
|
||||
def sever_crashed(server_id):
|
||||
with database.atomic():
|
||||
Server_Stats.update(crashed=True).where(
|
||||
Server_Stats.server_id == server_id
|
||||
).execute()
|
||||
|
||||
@staticmethod
|
||||
def set_download(server_id):
|
||||
with database.atomic():
|
||||
Server_Stats.update(downloading=True).where(
|
||||
Server_Stats.server_id == server_id
|
||||
).execute()
|
||||
|
||||
@staticmethod
|
||||
def finish_download(server_id):
|
||||
with database.atomic():
|
||||
Server_Stats.update(downloading=False).where(
|
||||
Server_Stats.server_id == server_id
|
||||
).execute()
|
||||
|
||||
@staticmethod
|
||||
def get_download_status(server_id):
|
||||
download_status = (
|
||||
Server_Stats.select().where(Server_Stats.server_id == server_id).get()
|
||||
)
|
||||
return download_status.downloading
|
||||
|
||||
@staticmethod
|
||||
def server_crash_reset(server_id):
|
||||
with database.atomic():
|
||||
Server_Stats.update(crashed=False).where(
|
||||
Server_Stats.server_id == server_id
|
||||
).execute()
|
||||
|
||||
@staticmethod
|
||||
def is_crashed(server_id):
|
||||
svr = Server_Stats.select().where(Server_Stats.server_id == server_id).get()
|
||||
# pylint: disable=singleton-comparison
|
||||
if svr.crashed == True:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def set_update(server_id, value):
|
||||
try:
|
||||
# Checks if server even exists
|
||||
Server_Stats.select().where(Server_Stats.server_id == server_id)
|
||||
except Exception as ex:
|
||||
logger.error(f"Database entry not found! {ex}")
|
||||
with database.atomic():
|
||||
Server_Stats.update(updating=value).where(
|
||||
Server_Stats.server_id == server_id
|
||||
).execute()
|
||||
|
||||
@staticmethod
|
||||
def get_update_status(server_id):
|
||||
update_status = (
|
||||
Server_Stats.select().where(Server_Stats.server_id == server_id).get()
|
||||
)
|
||||
return update_status.updating
|
||||
|
||||
@staticmethod
|
||||
def set_first_run(server_id):
|
||||
# Sets first run to false
|
||||
try:
|
||||
# Checks if server even exists
|
||||
Server_Stats.select().where(Server_Stats.server_id == server_id)
|
||||
except Exception as ex:
|
||||
logger.error(f"Database entry not found! {ex}")
|
||||
return
|
||||
with database.atomic():
|
||||
Server_Stats.update(first_run=False).where(
|
||||
Server_Stats.server_id == server_id
|
||||
).execute()
|
||||
|
||||
@staticmethod
|
||||
def get_first_run(server_id):
|
||||
first_run = (
|
||||
Server_Stats.select().where(Server_Stats.server_id == server_id).get()
|
||||
)
|
||||
return first_run.first_run
|
||||
|
||||
@staticmethod
|
||||
def get_TTL_without_player(server_id):
|
||||
last_stat = (
|
||||
Server_Stats.select()
|
||||
.where(Server_Stats.server_id == server_id)
|
||||
.order_by(Server_Stats.created.desc())
|
||||
.first()
|
||||
)
|
||||
last_stat_with_player = (
|
||||
Server_Stats.select()
|
||||
.where(Server_Stats.server_id == server_id)
|
||||
.where(Server_Stats.online > 0)
|
||||
.order_by(Server_Stats.created.desc())
|
||||
.first()
|
||||
)
|
||||
return last_stat.created - last_stat_with_player.created
|
||||
|
||||
@staticmethod
|
||||
def can_stop_no_players(server_id, time_limit):
|
||||
can = False
|
||||
ttl_no_players = servers_helper.get_TTL_without_player(server_id)
|
||||
if (time_limit == -1) or (ttl_no_players > time_limit):
|
||||
can = True
|
||||
return can
|
||||
|
||||
@staticmethod
|
||||
def set_waiting_start(server_id, value):
|
||||
try:
|
||||
# Checks if server even exists
|
||||
Server_Stats.select().where(Server_Stats.server_id == server_id)
|
||||
except Exception as ex:
|
||||
logger.error(f"Database entry not found! {ex}")
|
||||
with database.atomic():
|
||||
Server_Stats.update(waiting_start=value).where(
|
||||
Server_Stats.server_id == server_id
|
||||
).execute()
|
||||
|
||||
@staticmethod
|
||||
def get_waiting_start(server_id):
|
||||
waiting_start = (
|
||||
Server_Stats.select().where(Server_Stats.server_id == server_id).get()
|
||||
)
|
||||
return waiting_start.waiting_start
|
||||
|
||||
|
||||
servers_helper = helper_servers()
|
||||
|
@ -2,38 +2,28 @@ import logging
|
||||
import datetime
|
||||
from typing import Optional, Union
|
||||
|
||||
from app.classes.models.roles import Roles, roles_helper
|
||||
from app.classes.shared.helpers import helper
|
||||
from peewee import (
|
||||
ForeignKeyField,
|
||||
CharField,
|
||||
AutoField,
|
||||
DateTimeField,
|
||||
BooleanField,
|
||||
CompositeKey,
|
||||
DoesNotExist,
|
||||
JOIN,
|
||||
)
|
||||
from playhouse.shortcuts import model_to_dict
|
||||
|
||||
try:
|
||||
from peewee import (
|
||||
SqliteDatabase,
|
||||
Model,
|
||||
ForeignKeyField,
|
||||
CharField,
|
||||
AutoField,
|
||||
DateTimeField,
|
||||
BooleanField,
|
||||
CompositeKey,
|
||||
DoesNotExist,
|
||||
JOIN,
|
||||
)
|
||||
from playhouse.shortcuts import model_to_dict
|
||||
|
||||
except ModuleNotFoundError as e:
|
||||
helper.auto_installer_fix(e)
|
||||
from app.classes.shared.helpers import Helpers
|
||||
from app.classes.models.base_model import BaseModel
|
||||
from app.classes.models.roles import Roles, HelperRoles
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
peewee_logger = logging.getLogger("peewee")
|
||||
peewee_logger.setLevel(logging.INFO)
|
||||
database = SqliteDatabase(
|
||||
helper.db_path, pragmas={"journal_mode": "wal", "cache_size": -1024 * 10}
|
||||
)
|
||||
|
||||
# **********************************************************************************
|
||||
# Users Class
|
||||
# **********************************************************************************
|
||||
class Users(Model):
|
||||
class Users(BaseModel):
|
||||
user_id = AutoField()
|
||||
created = DateTimeField(default=datetime.datetime.now)
|
||||
last_login = DateTimeField(default=datetime.datetime.now)
|
||||
@ -49,16 +39,16 @@ class Users(Model):
|
||||
valid_tokens_from = DateTimeField(default=datetime.datetime.now)
|
||||
server_order = CharField(default="")
|
||||
preparing = BooleanField(default=False)
|
||||
hints = BooleanField(default=True)
|
||||
|
||||
class Meta:
|
||||
table_name = "users"
|
||||
database = database
|
||||
|
||||
|
||||
# **********************************************************************************
|
||||
# API Keys Class
|
||||
# **********************************************************************************
|
||||
class ApiKeys(Model):
|
||||
class ApiKeys(BaseModel):
|
||||
token_id = AutoField()
|
||||
name = CharField(default="", unique=True, index=True)
|
||||
created = DateTimeField(default=datetime.datetime.now)
|
||||
@ -69,26 +59,28 @@ class ApiKeys(Model):
|
||||
|
||||
class Meta:
|
||||
table_name = "api_keys"
|
||||
database = database
|
||||
|
||||
|
||||
# **********************************************************************************
|
||||
# User Roles Class
|
||||
# **********************************************************************************
|
||||
class User_Roles(Model):
|
||||
class UserRoles(BaseModel):
|
||||
user_id = ForeignKeyField(Users, backref="user_role")
|
||||
role_id = ForeignKeyField(Roles, backref="user_role")
|
||||
|
||||
class Meta:
|
||||
table_name = "user_roles"
|
||||
primary_key = CompositeKey("user_id", "role_id")
|
||||
database = database
|
||||
|
||||
|
||||
# **********************************************************************************
|
||||
# Users Helpers
|
||||
# **********************************************************************************
|
||||
class helper_users:
|
||||
class HelperUsers:
|
||||
def __init__(self, database, helper):
|
||||
self.database = database
|
||||
self.helper = helper
|
||||
|
||||
@staticmethod
|
||||
def get_by_id(user_id):
|
||||
return Users.get_by_id(user_id)
|
||||
@ -136,7 +128,7 @@ class helper_users:
|
||||
|
||||
if user:
|
||||
# I know it should apply it without setting it but I'm just making sure
|
||||
user = users_helper.add_user_roles(user)
|
||||
user = HelperUsers.add_user_roles(user)
|
||||
return user
|
||||
else:
|
||||
# logger.debug("user: ({}) {}".format(user_id, {}))
|
||||
@ -154,11 +146,11 @@ class helper_users:
|
||||
@staticmethod
|
||||
def get_user_model(user_id: str) -> Users:
|
||||
user = Users.get(Users.user_id == user_id)
|
||||
user = users_helper.add_user_roles(user)
|
||||
user = HelperUsers.add_user_roles(user)
|
||||
return user
|
||||
|
||||
@staticmethod
|
||||
def add_user(
|
||||
self,
|
||||
username: str,
|
||||
password: str = None,
|
||||
email: Optional[str] = None,
|
||||
@ -166,7 +158,7 @@ class helper_users:
|
||||
superuser: bool = False,
|
||||
) -> str:
|
||||
if password is not None:
|
||||
pw_enc = helper.encode_pass(password)
|
||||
pw_enc = self.helper.encode_pass(password)
|
||||
else:
|
||||
pw_enc = None
|
||||
user_id = Users.insert(
|
||||
@ -176,7 +168,7 @@ class helper_users:
|
||||
Users.email: email,
|
||||
Users.enabled: enabled,
|
||||
Users.superuser: superuser,
|
||||
Users.created: helper.get_time_as_string(),
|
||||
Users.created: Helpers.get_time_as_string(),
|
||||
}
|
||||
).execute()
|
||||
return user_id
|
||||
@ -196,7 +188,7 @@ class helper_users:
|
||||
Users.email: email,
|
||||
Users.enabled: enabled,
|
||||
Users.superuser: superuser,
|
||||
Users.created: helper.get_time_as_string(),
|
||||
Users.created: Helpers.get_time_as_string(),
|
||||
}
|
||||
).execute()
|
||||
return user_id
|
||||
@ -221,17 +213,17 @@ class helper_users:
|
||||
@staticmethod
|
||||
def get_super_user_list():
|
||||
final_users = []
|
||||
# pylint: disable=singleton-comparison
|
||||
super_users = Users.select().where(Users.superuser == True)
|
||||
super_users = Users.select().where(
|
||||
Users.superuser == True # pylint: disable=singleton-comparison
|
||||
)
|
||||
for suser in super_users:
|
||||
if suser.user_id not in final_users:
|
||||
final_users.append(suser.user_id)
|
||||
return final_users
|
||||
|
||||
@staticmethod
|
||||
def remove_user(user_id):
|
||||
with database.atomic():
|
||||
User_Roles.delete().where(User_Roles.user_id == user_id).execute()
|
||||
def remove_user(self, user_id):
|
||||
with self.database.atomic():
|
||||
UserRoles.delete().where(UserRoles.user_id == user_id).execute()
|
||||
user = Users.get(Users.user_id == user_id)
|
||||
return user.delete_instance()
|
||||
|
||||
@ -251,12 +243,13 @@ class helper_users:
|
||||
|
||||
@staticmethod
|
||||
def clear_support_status():
|
||||
# pylint: disable=singleton-comparison
|
||||
Users.update(preparing=False).where(Users.preparing == True).execute()
|
||||
Users.update(preparing=False).where(
|
||||
Users.preparing == True # pylint: disable=singleton-comparison
|
||||
).execute()
|
||||
|
||||
@staticmethod
|
||||
def user_id_exists(user_id):
|
||||
if not users_helper.get_user(user_id):
|
||||
if not HelperUsers.get_user(user_id):
|
||||
return False
|
||||
return True
|
||||
|
||||
@ -266,28 +259,28 @@ class helper_users:
|
||||
|
||||
@staticmethod
|
||||
def get_or_create(user_id, role_id):
|
||||
return User_Roles.get_or_create(user_id=user_id, role_id=role_id)
|
||||
return UserRoles.get_or_create(user_id=user_id, role_id=role_id)
|
||||
|
||||
@staticmethod
|
||||
def get_user_roles_id(user_id):
|
||||
roles_list = []
|
||||
roles = User_Roles.select().where(User_Roles.user_id == user_id)
|
||||
roles = UserRoles.select().where(UserRoles.user_id == user_id)
|
||||
for r in roles:
|
||||
roles_list.append(roles_helper.get_role(r.role_id)["role_id"])
|
||||
roles_list.append(HelperRoles.get_role(r.role_id)["role_id"])
|
||||
return roles_list
|
||||
|
||||
@staticmethod
|
||||
def get_user_roles_names(user_id):
|
||||
roles_list = []
|
||||
roles = User_Roles.select().where(User_Roles.user_id == user_id)
|
||||
roles = UserRoles.select().where(UserRoles.user_id == user_id)
|
||||
for r in roles:
|
||||
roles_list.append(roles_helper.get_role(r.role_id)["role_name"])
|
||||
roles_list.append(HelperRoles.get_role(r.role_id)["role_name"])
|
||||
return roles_list
|
||||
|
||||
@staticmethod
|
||||
def add_role_to_user(user_id, role_id):
|
||||
User_Roles.insert(
|
||||
{User_Roles.user_id: user_id, User_Roles.role_id: role_id}
|
||||
UserRoles.insert(
|
||||
{UserRoles.user_id: user_id, UserRoles.role_id: role_id}
|
||||
).execute()
|
||||
|
||||
@staticmethod
|
||||
@ -301,9 +294,9 @@ class helper_users:
|
||||
# it had those TODOs & comments made by mac - Lukas
|
||||
|
||||
roles_query = (
|
||||
User_Roles.select()
|
||||
UserRoles.select()
|
||||
.join(Roles, JOIN.INNER)
|
||||
.where(User_Roles.user_id == user_id)
|
||||
.where(UserRoles.user_id == user_id)
|
||||
)
|
||||
# TODO: this query needs to be narrower
|
||||
roles = set()
|
||||
@ -320,21 +313,21 @@ class helper_users:
|
||||
|
||||
@staticmethod
|
||||
def user_role_query(user_id):
|
||||
user_query = User_Roles.select().where(User_Roles.user_id == user_id)
|
||||
user_query = UserRoles.select().where(UserRoles.user_id == user_id)
|
||||
query = Roles.select().where(Roles.role_id == -1)
|
||||
for u in user_query:
|
||||
query = query + Roles.select().where(Roles.role_id == u.role_id)
|
||||
for user in user_query:
|
||||
query = query + Roles.select().where(Roles.role_id == user.role_id)
|
||||
return query
|
||||
|
||||
@staticmethod
|
||||
def delete_user_roles(user_id, removed_roles):
|
||||
User_Roles.delete().where(User_Roles.user_id == user_id).where(
|
||||
User_Roles.role_id.in_(removed_roles)
|
||||
UserRoles.delete().where(UserRoles.user_id == user_id).where(
|
||||
UserRoles.role_id.in_(removed_roles)
|
||||
).execute()
|
||||
|
||||
@staticmethod
|
||||
def remove_roles_from_role_id(role_id):
|
||||
User_Roles.delete().where(User_Roles.role_id == role_id).execute()
|
||||
UserRoles.delete().where(UserRoles.role_id == role_id).execute()
|
||||
|
||||
# **********************************************************************************
|
||||
# ApiKeys Methods
|
||||
@ -381,6 +374,3 @@ class helper_users:
|
||||
@staticmethod
|
||||
def delete_user_api_key(key_id: str):
|
||||
ApiKeys.delete().where(ApiKeys.token_id == key_id).execute()
|
||||
|
||||
|
||||
users_helper = helper_users()
|
||||
|
@ -1,56 +1,50 @@
|
||||
import logging
|
||||
import time
|
||||
from typing import Optional, Dict, Any, Tuple
|
||||
import jwt
|
||||
from jwt import PyJWTError
|
||||
|
||||
from app.classes.models.users import users_helper, ApiKeys
|
||||
from app.classes.shared.helpers import helper
|
||||
|
||||
try:
|
||||
import jwt
|
||||
from jwt import PyJWTError
|
||||
|
||||
except ModuleNotFoundError as e:
|
||||
helper.auto_installer_fix(e)
|
||||
from app.classes.models.users import HelperUsers, ApiKeys
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Authentication:
|
||||
def __init__(self):
|
||||
def __init__(self, helper):
|
||||
self.helper = helper
|
||||
self.secret = "my secret"
|
||||
self.secret = helper.get_setting("apikey_secret", None)
|
||||
self.secret = self.helper.get_setting("apikey_secret", None)
|
||||
|
||||
if self.secret is None or self.secret == "random":
|
||||
self.secret = helper.random_string_generator(64)
|
||||
self.secret = self.helper.random_string_generator(64)
|
||||
self.helper.set_setting("apikey_secret", self.secret)
|
||||
|
||||
@staticmethod
|
||||
def generate(user_id, extra=None):
|
||||
def generate(self, user_id, extra=None):
|
||||
if extra is None:
|
||||
extra = {}
|
||||
return jwt.encode(
|
||||
jwt_encoded = jwt.encode(
|
||||
{"user_id": user_id, "iat": int(time.time()), **extra},
|
||||
authentication.secret,
|
||||
self.secret,
|
||||
algorithm="HS256",
|
||||
)
|
||||
return jwt_encoded
|
||||
|
||||
@staticmethod
|
||||
def read(token):
|
||||
return jwt.decode(token, authentication.secret, algorithms=["HS256"])
|
||||
def read(self, token):
|
||||
return jwt.decode(token, self.secret, algorithms=["HS256"])
|
||||
|
||||
@staticmethod
|
||||
def check_no_iat(token) -> Optional[Dict[str, Any]]:
|
||||
def check_no_iat(self, token) -> Optional[Dict[str, Any]]:
|
||||
try:
|
||||
return jwt.decode(token, authentication.secret, algorithms=["HS256"])
|
||||
return jwt.decode(token, self.secret, algorithms=["HS256"])
|
||||
except PyJWTError as error:
|
||||
logger.debug("Error while checking JWT token: ", exc_info=error)
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def check(
|
||||
self,
|
||||
token,
|
||||
) -> Optional[Tuple[Optional[ApiKeys], Dict[str, Any], Dict[str, Any]]]:
|
||||
try:
|
||||
data = jwt.decode(token, authentication.secret, algorithms=["HS256"])
|
||||
data = jwt.decode(token, self.secret, algorithms=["HS256"])
|
||||
except PyJWTError as error:
|
||||
logger.debug("Error while checking JWT token: ", exc_info=error)
|
||||
return None
|
||||
@ -58,11 +52,11 @@ class Authentication:
|
||||
key: Optional[ApiKeys] = None
|
||||
if "token_id" in data:
|
||||
key_id = data["token_id"]
|
||||
key = users_helper.get_user_api_key(key_id)
|
||||
key = HelperUsers.get_user_api_key(key_id)
|
||||
if key is None:
|
||||
return None
|
||||
user_id: str = data["user_id"]
|
||||
user = users_helper.get_user(user_id)
|
||||
user = HelperUsers.get_user(user_id)
|
||||
# TODO: Have a cache or something so we don't constantly
|
||||
# have to query the database
|
||||
if int(user.get("valid_tokens_from").timestamp()) < iat:
|
||||
@ -71,9 +65,5 @@ class Authentication:
|
||||
else:
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def check_bool(token) -> bool:
|
||||
return authentication.check(token) is not None
|
||||
|
||||
|
||||
authentication = Authentication()
|
||||
def check_bool(self, token) -> bool:
|
||||
return self.check(token) is not None
|
||||
|
@ -3,30 +3,28 @@ import cmd
|
||||
import time
|
||||
import threading
|
||||
import logging
|
||||
from app.classes.shared.console import Console
|
||||
|
||||
from app.classes.shared.console import console
|
||||
from app.classes.shared.helpers import helper
|
||||
from app.classes.shared.import3 import import3
|
||||
from app.classes.web.websocket_helper import websocket_helper
|
||||
from app.classes.shared.import3 import Import3
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class MainPrompt(cmd.Cmd):
|
||||
def __init__(self, tasks_manager, migration_manager):
|
||||
def __init__(self, helper, tasks_manager, migration_manager):
|
||||
super().__init__()
|
||||
self.helper = helper
|
||||
self.tasks_manager = tasks_manager
|
||||
self.migration_manager = migration_manager
|
||||
# overrides the default Prompt
|
||||
self.prompt = f"Crafty Controller v{self.helper.get_version_string()} > "
|
||||
|
||||
# overrides the default Prompt
|
||||
prompt = f"Crafty Controller v{helper.get_version_string()} > "
|
||||
|
||||
# see MR !233 for pylint exemptino reason
|
||||
@staticmethod
|
||||
def emptyline():
|
||||
def emptyline(): # pylint: disable=arguments-differ
|
||||
pass
|
||||
|
||||
# pylint: disable=unused-argument
|
||||
def do_exit(self, line):
|
||||
def do_exit(self, _line):
|
||||
self.tasks_manager._main_graceful_exit()
|
||||
self.universal_exit()
|
||||
|
||||
@ -36,20 +34,20 @@ class MainPrompt(cmd.Cmd):
|
||||
elif line == "down":
|
||||
self.migration_manager.down()
|
||||
elif line == "done":
|
||||
console.info(self.migration_manager.done)
|
||||
Console.info(self.migration_manager.done)
|
||||
elif line == "todo":
|
||||
console.info(self.migration_manager.todo)
|
||||
Console.info(self.migration_manager.todo)
|
||||
elif line == "diff":
|
||||
console.info(self.migration_manager.diff)
|
||||
Console.info(self.migration_manager.diff)
|
||||
elif line == "info":
|
||||
console.info(f"Done: {self.migration_manager.done}")
|
||||
console.info(f"FS: {self.migration_manager.todo}")
|
||||
console.info(f"Todo: {self.migration_manager.diff}")
|
||||
Console.info(f"Done: {self.migration_manager.done}")
|
||||
Console.info(f"FS: {self.migration_manager.todo}")
|
||||
Console.info(f"Todo: {self.migration_manager.diff}")
|
||||
elif line.startswith("add "):
|
||||
migration_name = line[len("add ") :]
|
||||
self.migration_manager.create(migration_name, False)
|
||||
else:
|
||||
console.info("Unknown migration command")
|
||||
Console.info("Unknown migration command")
|
||||
|
||||
@staticmethod
|
||||
def do_threads(_line):
|
||||
@ -63,28 +61,25 @@ class MainPrompt(cmd.Cmd):
|
||||
print(f"Name: {thread.name} Identifier: {thread.ident}")
|
||||
|
||||
def do_import3(self, _line):
|
||||
import3.start_import()
|
||||
Import3.start_import()
|
||||
|
||||
def universal_exit(self):
|
||||
logger.info("Stopping all server daemons / threads")
|
||||
console.info(
|
||||
Console.info(
|
||||
"Stopping all server daemons / threads - This may take a few seconds"
|
||||
)
|
||||
websocket_helper.disconnect_all()
|
||||
console.info("Waiting for main thread to stop")
|
||||
self.helper.websocket_helper.disconnect_all()
|
||||
Console.info("Waiting for main thread to stop")
|
||||
while True:
|
||||
if self.tasks_manager.get_main_thread_run_status():
|
||||
sys.exit(0)
|
||||
time.sleep(1)
|
||||
|
||||
@staticmethod
|
||||
def help_exit():
|
||||
console.help("Stops the server if running, Exits the program")
|
||||
def help_exit(self):
|
||||
Console.help("Stops the server if running, Exits the program")
|
||||
|
||||
@staticmethod
|
||||
def help_migrations():
|
||||
console.help("Only for advanced users. Use with caution")
|
||||
def help_migrations(self):
|
||||
Console.help("Only for advanced users. Use with caution")
|
||||
|
||||
@staticmethod
|
||||
def help_import3():
|
||||
console.help("Import users and servers from Crafty 3")
|
||||
def help_import3(self):
|
||||
Console.help("Import users and servers from Crafty 3")
|
||||
|
@ -28,47 +28,56 @@ class Console:
|
||||
else:
|
||||
print(message)
|
||||
|
||||
def magenta(self, message):
|
||||
self.do_print(message, "magenta")
|
||||
@staticmethod
|
||||
def magenta(message):
|
||||
Console.do_print(message, "magenta")
|
||||
|
||||
def cyan(self, message):
|
||||
self.do_print(message, "cyan")
|
||||
@staticmethod
|
||||
def cyan(message):
|
||||
Console.do_print(message, "cyan")
|
||||
|
||||
def yellow(self, message):
|
||||
self.do_print(message, "yellow")
|
||||
@staticmethod
|
||||
def yellow(message):
|
||||
Console.do_print(message, "yellow")
|
||||
|
||||
def red(self, message):
|
||||
self.do_print(message, "red")
|
||||
@staticmethod
|
||||
def red(message):
|
||||
Console.do_print(message, "red")
|
||||
|
||||
def green(self, message):
|
||||
self.do_print(message, "green")
|
||||
@staticmethod
|
||||
def green(message):
|
||||
Console.do_print(message, "green")
|
||||
|
||||
def white(self, message):
|
||||
self.do_print(message, "white")
|
||||
@staticmethod
|
||||
def white(message):
|
||||
Console.do_print(message, "white")
|
||||
|
||||
def debug(self, message):
|
||||
dt = datetime.datetime.now().strftime("%Y-%m-%d %I:%M:%S %p")
|
||||
self.magenta(f"[+] Crafty: {dt} - DEBUG:\t{message}")
|
||||
@staticmethod
|
||||
def debug(message):
|
||||
date_time = datetime.datetime.now().strftime("%Y-%m-%d %I:%M:%S %p")
|
||||
Console.magenta(f"[+] Crafty: {date_time} - DEBUG:\t{message}")
|
||||
|
||||
def info(self, message):
|
||||
dt = datetime.datetime.now().strftime("%Y-%m-%d %I:%M:%S %p")
|
||||
self.white(f"[+] Crafty: {dt} - INFO:\t{message}")
|
||||
@staticmethod
|
||||
def info(message):
|
||||
date_time = datetime.datetime.now().strftime("%Y-%m-%d %I:%M:%S %p")
|
||||
Console.white(f"[+] Crafty: {date_time} - INFO:\t{message}")
|
||||
|
||||
def warning(self, message):
|
||||
dt = datetime.datetime.now().strftime("%Y-%m-%d %I:%M:%S %p")
|
||||
self.cyan(f"[+] Crafty: {dt} - WARNING:\t{message}")
|
||||
@staticmethod
|
||||
def warning(message):
|
||||
date_time = datetime.datetime.now().strftime("%Y-%m-%d %I:%M:%S %p")
|
||||
Console.cyan(f"[+] Crafty: {date_time} - WARNING:\t{message}")
|
||||
|
||||
def error(self, message):
|
||||
dt = datetime.datetime.now().strftime("%Y-%m-%d %I:%M:%S %p")
|
||||
self.yellow(f"[+] Crafty: {dt} - ERROR:\t{message}")
|
||||
@staticmethod
|
||||
def error(message):
|
||||
date_time = datetime.datetime.now().strftime("%Y-%m-%d %I:%M:%S %p")
|
||||
Console.yellow(f"[+] Crafty: {date_time} - ERROR:\t{message}")
|
||||
|
||||
def critical(self, message):
|
||||
dt = datetime.datetime.now().strftime("%Y-%m-%d %I:%M:%S %p")
|
||||
self.red(f"[+] Crafty: {dt} - CRITICAL:\t{message}")
|
||||
@staticmethod
|
||||
def critical(message):
|
||||
date_time = datetime.datetime.now().strftime("%Y-%m-%d %I:%M:%S %p")
|
||||
Console.red(f"[+] Crafty: {date_time} - CRITICAL:\t{message}")
|
||||
|
||||
def help(self, message):
|
||||
dt = datetime.datetime.now().strftime("%Y-%m-%d %I:%M:%S %p")
|
||||
self.green(f"[+] Crafty: {dt} - HELP:\t{message}")
|
||||
|
||||
|
||||
console = Console()
|
||||
@staticmethod
|
||||
def help(message):
|
||||
date_time = datetime.datetime.now().strftime("%Y-%m-%d %I:%M:%S %p")
|
||||
Console.green(f"[+] Crafty: {date_time} - HELP:\t{message}")
|
||||
|
@ -10,12 +10,13 @@ logger = logging.getLogger(__name__)
|
||||
class FileHelpers:
|
||||
allowed_quotes = ['"', "'", "`"]
|
||||
|
||||
def del_dirs(self, path):
|
||||
@staticmethod
|
||||
def del_dirs(path):
|
||||
path = pathlib.Path(path)
|
||||
for sub in path.iterdir():
|
||||
if sub.is_dir():
|
||||
# Delete folder if it is a folder
|
||||
self.del_dirs(sub)
|
||||
FileHelpers.del_dirs(sub)
|
||||
else:
|
||||
# Delete file if it is a file:
|
||||
sub.unlink()
|
||||
@ -45,31 +46,33 @@ class FileHelpers:
|
||||
def copy_file(src_path, dest_path):
|
||||
shutil.copy(src_path, dest_path)
|
||||
|
||||
def move_dir(self, src_path, dest_path):
|
||||
self.copy_dir(src_path, dest_path)
|
||||
self.del_dirs(src_path)
|
||||
@staticmethod
|
||||
def move_dir(src_path, dest_path):
|
||||
FileHelpers.copy_dir(src_path, dest_path)
|
||||
FileHelpers.del_dirs(src_path)
|
||||
|
||||
def move_file(self, src_path, dest_path):
|
||||
self.copy_file(src_path, dest_path)
|
||||
self.del_file(src_path)
|
||||
@staticmethod
|
||||
def move_file(src_path, dest_path):
|
||||
FileHelpers.copy_file(src_path, dest_path)
|
||||
FileHelpers.del_file(src_path)
|
||||
|
||||
@staticmethod
|
||||
def make_archive(path_to_destination, path_to_zip):
|
||||
# create a ZipFile object
|
||||
path_to_destination += ".zip"
|
||||
with ZipFile(path_to_destination, "w") as z:
|
||||
with ZipFile(path_to_destination, "w") as zip_file:
|
||||
for root, _dirs, files in os.walk(path_to_zip, topdown=True):
|
||||
ziproot = path_to_zip
|
||||
for file in files:
|
||||
try:
|
||||
logger.info(f"backing up: {os.path.join(root, file)}")
|
||||
if os.name == "nt":
|
||||
z.write(
|
||||
zip_file.write(
|
||||
os.path.join(root, file),
|
||||
os.path.join(root.replace(ziproot, ""), file),
|
||||
)
|
||||
else:
|
||||
z.write(
|
||||
zip_file.write(
|
||||
os.path.join(root, file),
|
||||
os.path.join(root.replace(ziproot, "/"), file),
|
||||
)
|
||||
@ -86,19 +89,19 @@ class FileHelpers:
|
||||
def make_compressed_archive(path_to_destination, path_to_zip):
|
||||
# create a ZipFile object
|
||||
path_to_destination += ".zip"
|
||||
with ZipFile(path_to_destination, "w", ZIP_DEFLATED) as z:
|
||||
with ZipFile(path_to_destination, "w", ZIP_DEFLATED) as zip_file:
|
||||
for root, _dirs, files in os.walk(path_to_zip, topdown=True):
|
||||
ziproot = path_to_zip
|
||||
for file in files:
|
||||
try:
|
||||
logger.info(f"backing up: {os.path.join(root, file)}")
|
||||
if os.name == "nt":
|
||||
z.write(
|
||||
zip_file.write(
|
||||
os.path.join(root, file),
|
||||
os.path.join(root.replace(ziproot, ""), file),
|
||||
)
|
||||
else:
|
||||
z.write(
|
||||
zip_file.write(
|
||||
os.path.join(root, file),
|
||||
os.path.join(root.replace(ziproot, "/"), file),
|
||||
)
|
||||
@ -110,6 +113,3 @@ class FileHelpers:
|
||||
)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
file_helper = FileHelpers()
|
||||
|
@ -19,10 +19,11 @@ from socket import gethostname
|
||||
from contextlib import suppress
|
||||
import psutil
|
||||
|
||||
from app.classes.shared.console import console
|
||||
from app.classes.shared.console import Console
|
||||
from app.classes.shared.installer import installer
|
||||
from app.classes.shared.file_helpers import file_helper
|
||||
from app.classes.web.websocket_helper import websocket_helper
|
||||
from app.classes.shared.file_helpers import FileHelpers
|
||||
from app.classes.shared.translation import Translation
|
||||
from app.classes.web.websocket_helper import WebSocketHelper
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@ -61,17 +62,22 @@ class Helpers:
|
||||
self.passhasher = PasswordHasher()
|
||||
self.exiting = False
|
||||
|
||||
self.websocket_helper = WebSocketHelper(self)
|
||||
self.translation = Translation(self)
|
||||
|
||||
@staticmethod
|
||||
def auto_installer_fix(ex):
|
||||
logger.critical(f"Import Error: Unable to load {ex.name} module", exc_info=True)
|
||||
print(f"Import Error: Unable to load {ex.name} module")
|
||||
installer.do_install()
|
||||
|
||||
def float_to_string(self, gbs: int):
|
||||
@staticmethod
|
||||
def float_to_string(gbs: int):
|
||||
s = str(float(gbs) * 1000).rstrip("0").rstrip(".")
|
||||
return s
|
||||
|
||||
def check_file_perms(self, path):
|
||||
@staticmethod
|
||||
def check_file_perms(path):
|
||||
try:
|
||||
open(path, "r", encoding="utf-8").close()
|
||||
logger.info(f"{path} is readable")
|
||||
@ -79,8 +85,9 @@ class Helpers:
|
||||
except PermissionError:
|
||||
return False
|
||||
|
||||
def is_file_older_than_x_days(self, file, days=1):
|
||||
if self.check_file_exists(file):
|
||||
@staticmethod
|
||||
def is_file_older_than_x_days(file, days=1):
|
||||
if Helpers.check_file_exists(file):
|
||||
file_time = os.path.getmtime(file)
|
||||
# Check against 24 hours
|
||||
if (time.time() - file_time) / 3600 > 24 * days:
|
||||
@ -139,47 +146,51 @@ class Helpers:
|
||||
def cmdparse(cmd_in):
|
||||
# Parse a string into arguments
|
||||
cmd_out = [] # "argv" output array
|
||||
ci = -1 # command index - pointer to the argument we're building in cmd_out
|
||||
np = True # whether we're creating a new argument/parameter
|
||||
cmd_index = (
|
||||
-1
|
||||
) # command index - pointer to the argument we're building in cmd_out
|
||||
new_param = True # whether we're creating a new argument/parameter
|
||||
esc = False # whether an escape character was encountered
|
||||
stch = None # if we're dealing with a quote, save the quote type here.
|
||||
quote_char = None # if we're dealing with a quote, save the quote type here.
|
||||
# Nested quotes to be dealt with by the command
|
||||
for c in cmd_in: # for character in string
|
||||
if np: # if set, begin a new argument and increment the command index.
|
||||
for char in cmd_in: # for character in string
|
||||
if (
|
||||
new_param
|
||||
): # if set, begin a new argument and increment the command index.
|
||||
# Continue the loop.
|
||||
if c == " ":
|
||||
if char == " ":
|
||||
continue
|
||||
else:
|
||||
ci += 1
|
||||
cmd_index += 1
|
||||
cmd_out.append("")
|
||||
np = False
|
||||
new_param = False
|
||||
if esc: # if we encountered an escape character on the last loop,
|
||||
# append this char regardless of what it is
|
||||
if c not in Helpers.allowed_quotes:
|
||||
cmd_out[ci] += "\\"
|
||||
cmd_out[ci] += c
|
||||
if char not in Helpers.allowed_quotes:
|
||||
cmd_out[cmd_index] += "\\"
|
||||
cmd_out[cmd_index] += char
|
||||
esc = False
|
||||
else:
|
||||
if c == "\\": # if the current character is an escape character,
|
||||
if char == "\\": # if the current character is an escape character,
|
||||
# set the esc flag and continue to next loop
|
||||
esc = True
|
||||
elif (
|
||||
c == " " and stch is None
|
||||
char == " " and quote_char is None
|
||||
): # if we encounter a space and are not dealing with a quote,
|
||||
# set the new argument flag and continue to next loop
|
||||
np = True
|
||||
new_param = True
|
||||
elif (
|
||||
c == stch
|
||||
char == quote_char
|
||||
): # if we encounter the character that matches our start quote,
|
||||
# end the quote and continue to next loop
|
||||
stch = None
|
||||
elif stch is None and (
|
||||
c in Helpers.allowed_quotes
|
||||
quote_char = None
|
||||
elif quote_char is None and (
|
||||
char in Helpers.allowed_quotes
|
||||
): # if we're not in the middle of a quote and we get a quotable
|
||||
# character, start a quote and proceed to the next loop
|
||||
stch = c
|
||||
quote_char = char
|
||||
else: # else, just store the character in the current arg
|
||||
cmd_out[ci] += c
|
||||
cmd_out[cmd_index] += char
|
||||
return cmd_out
|
||||
|
||||
def get_setting(self, key, default_return=False):
|
||||
@ -193,30 +204,56 @@ class Helpers:
|
||||
|
||||
else:
|
||||
logger.error(f"Config File Error: setting {key} does not exist")
|
||||
console.error(f"Config File Error: setting {key} does not exist")
|
||||
Console.error(f"Config File Error: setting {key} does not exist")
|
||||
return default_return
|
||||
|
||||
except Exception as e:
|
||||
logger.critical(
|
||||
f"Config File Error: Unable to read {self.settings_file} due to {e}"
|
||||
)
|
||||
console.critical(
|
||||
Console.critical(
|
||||
f"Config File Error: Unable to read {self.settings_file} due to {e}"
|
||||
)
|
||||
|
||||
return default_return
|
||||
|
||||
def get_local_ip(self):
|
||||
def set_setting(self, key, new_value, default_return=False):
|
||||
|
||||
try:
|
||||
with open(self.settings_file, "r", encoding="utf-8") as f:
|
||||
data = json.load(f)
|
||||
|
||||
if key in data.keys():
|
||||
data[key] = new_value
|
||||
|
||||
else:
|
||||
logger.error(f"Config File Error: setting {key} does not exist")
|
||||
Console.error(f"Config File Error: setting {key} does not exist")
|
||||
return default_return
|
||||
|
||||
with open(self.settings_file, "w", encoding="utf-8") as f:
|
||||
json.dump(data, f, indent=1)
|
||||
|
||||
except Exception as e:
|
||||
logger.critical(
|
||||
f"Config File Error: Unable to read {self.settings_file} due to {e}"
|
||||
)
|
||||
Console.critical(
|
||||
f"Config File Error: Unable to read {self.settings_file} due to {e}"
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def get_local_ip():
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
try:
|
||||
# doesn't even have to be reachable
|
||||
s.connect(("10.255.255.255", 1))
|
||||
IP = s.getsockname()[0]
|
||||
ip = s.getsockname()[0]
|
||||
except Exception:
|
||||
IP = "127.0.0.1"
|
||||
ip = "127.0.0.1"
|
||||
finally:
|
||||
s.close()
|
||||
return IP
|
||||
return ip
|
||||
|
||||
def get_version(self):
|
||||
version_data = {}
|
||||
@ -227,29 +264,28 @@ class Helpers:
|
||||
version_data = json.load(f)
|
||||
|
||||
except Exception as e:
|
||||
console.critical(f"Unable to get version data! \n{e}")
|
||||
Console.critical(f"Unable to get version data! \n{e}")
|
||||
|
||||
return version_data
|
||||
|
||||
@staticmethod
|
||||
def get_announcements():
|
||||
r = requests.get("https://craftycontrol.com/notify.json", timeout=2)
|
||||
response = requests.get("https://craftycontrol.com/notify.json", timeout=2)
|
||||
data = (
|
||||
'[{"id":"1","date":"Unknown",'
|
||||
'"title":"Error getting Announcements",'
|
||||
'"desc":"Error getting Announcements","link":""}]'
|
||||
)
|
||||
|
||||
if r.status_code in [200, 201]:
|
||||
if response.status_code in [200, 201]:
|
||||
try:
|
||||
data = json.loads(r.content)
|
||||
data = json.loads(response.content)
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to load json content with error: {e}")
|
||||
|
||||
return data
|
||||
|
||||
def get_version_string(self):
|
||||
|
||||
version_data = self.get_version()
|
||||
major = version_data.get("major", "?")
|
||||
minor = version_data.get("minor", "?")
|
||||
@ -306,19 +342,21 @@ class Helpers:
|
||||
|
||||
return line
|
||||
|
||||
def validate_traversal(self, base_path, filename):
|
||||
@staticmethod
|
||||
def validate_traversal(base_path, filename):
|
||||
logger.debug(f'Validating traversal ("{base_path}", "{filename}")')
|
||||
base = pathlib.Path(base_path).resolve()
|
||||
file = pathlib.Path(filename)
|
||||
fileabs = base.joinpath(file).resolve()
|
||||
cp = pathlib.Path(os.path.commonpath([base, fileabs]))
|
||||
if base == cp:
|
||||
common_path = pathlib.Path(os.path.commonpath([base, fileabs]))
|
||||
if base == common_path:
|
||||
return fileabs
|
||||
else:
|
||||
raise ValueError("Path traversal detected")
|
||||
|
||||
def tail_file(self, file_name, number_lines=20):
|
||||
if not self.check_file_exists(file_name):
|
||||
@staticmethod
|
||||
def tail_file(file_name, number_lines=20):
|
||||
if not Helpers.check_file_exists(file_name):
|
||||
logger.warning(f"Unable to find file to tail: {file_name}")
|
||||
return [f"Unable to find file to tail: {file_name}"]
|
||||
|
||||
@ -367,8 +405,9 @@ class Helpers:
|
||||
logger.critical(f"Unable to write to {path} - Error: {e}")
|
||||
return False
|
||||
|
||||
def checkRoot(self):
|
||||
if self.is_os_windows():
|
||||
@staticmethod
|
||||
def check_root():
|
||||
if Helpers.is_os_windows():
|
||||
if ctypes.windll.shell32.IsUserAnAdmin() == 1:
|
||||
return True
|
||||
else:
|
||||
@ -379,7 +418,8 @@ class Helpers:
|
||||
else:
|
||||
return False
|
||||
|
||||
def unzipFile(self, zip_path):
|
||||
@staticmethod
|
||||
def unzip_file(zip_path):
|
||||
new_dir_list = zip_path.split("/")
|
||||
new_dir = ""
|
||||
for i in range(len(new_dir_list) - 1):
|
||||
@ -388,28 +428,39 @@ class Helpers:
|
||||
else:
|
||||
new_dir += "/" + new_dir_list[i]
|
||||
|
||||
if helper.check_file_perms(zip_path) and os.path.isfile(zip_path):
|
||||
helper.ensure_dir_exists(new_dir)
|
||||
tempDir = tempfile.mkdtemp()
|
||||
if Helpers.check_file_perms(zip_path) and os.path.isfile(zip_path):
|
||||
Helpers.ensure_dir_exists(new_dir)
|
||||
temp_dir = tempfile.mkdtemp()
|
||||
try:
|
||||
with zipfile.ZipFile(zip_path, "r") as zip_ref:
|
||||
zip_ref.extractall(tempDir)
|
||||
zip_ref.extractall(temp_dir)
|
||||
for i in enumerate(zip_ref.filelist):
|
||||
if len(zip_ref.filelist) > 1 or not zip_ref.filelist[
|
||||
i
|
||||
].filename.endswith("/"):
|
||||
break
|
||||
|
||||
full_root_path = tempDir
|
||||
full_root_path = temp_dir
|
||||
|
||||
for item in os.listdir(full_root_path):
|
||||
try:
|
||||
file_helper.move_dir(
|
||||
os.path.join(full_root_path, item),
|
||||
os.path.join(new_dir, item),
|
||||
)
|
||||
except Exception as ex:
|
||||
logger.error(f"ERROR IN ZIP IMPORT: {ex}")
|
||||
print(item)
|
||||
if os.path.isdir(os.path.join(full_root_path, item)):
|
||||
print("dir")
|
||||
try:
|
||||
FileHelpers.move_dir(
|
||||
os.path.join(full_root_path, item),
|
||||
os.path.join(new_dir, item),
|
||||
)
|
||||
except Exception as ex:
|
||||
logger.error(f"ERROR IN ZIP IMPORT: {ex}")
|
||||
else:
|
||||
try:
|
||||
FileHelpers.move_file(
|
||||
os.path.join(full_root_path, item),
|
||||
os.path.join(new_dir, item),
|
||||
)
|
||||
except Exception as ex:
|
||||
logger.error(f"ERROR IN ZIP IMPORT: {ex}")
|
||||
except Exception as ex:
|
||||
print(ex)
|
||||
else:
|
||||
@ -422,7 +473,7 @@ class Helpers:
|
||||
|
||||
logger.info("Checking app directory writable")
|
||||
|
||||
writeable = self.check_writeable(self.root_dir)
|
||||
writeable = Helpers.check_writeable(self.root_dir)
|
||||
|
||||
# if not writeable, let's bomb out
|
||||
if not writeable:
|
||||
@ -434,13 +485,13 @@ class Helpers:
|
||||
with suppress(FileExistsError):
|
||||
os.makedirs(os.path.join(self.root_dir, "logs"))
|
||||
except Exception as e:
|
||||
console.error(f"Failed to make logs directory with error: {e} ")
|
||||
Console.error(f"Failed to make logs directory with error: {e} ")
|
||||
|
||||
# ensure the log file is there
|
||||
try:
|
||||
open(log_file, "a", encoding="utf-8").close()
|
||||
except Exception as e:
|
||||
console.critical(f"Unable to open log file! {e}")
|
||||
Console.critical(f"Unable to open log file! {e}")
|
||||
sys.exit(1)
|
||||
|
||||
# del any old session.lock file as this is a new session
|
||||
@ -461,16 +512,19 @@ class Helpers:
|
||||
source_size = 0
|
||||
files_count = 0
|
||||
for path, _dirs, files in os.walk(source_path):
|
||||
for f in files:
|
||||
fp = os.path.join(path, f)
|
||||
source_size += os.stat(fp).st_size
|
||||
for file in files:
|
||||
full_path = os.path.join(path, file)
|
||||
source_size += os.stat(full_path).st_size
|
||||
files_count += 1
|
||||
dest_size = os.path.getsize(str(dest_path))
|
||||
percent = round((dest_size / source_size) * 100, 1)
|
||||
try:
|
||||
dest_size = os.path.getsize(str(dest_path))
|
||||
percent = round((dest_size / source_size) * 100, 1)
|
||||
except:
|
||||
percent = 0
|
||||
if percent >= 0:
|
||||
results = {"percent": percent, "total_files": files_count}
|
||||
else:
|
||||
results = {"percent": 0, "total_files": 0}
|
||||
results = {"percent": 0, "total_files": files_count}
|
||||
return results
|
||||
|
||||
@staticmethod
|
||||
@ -540,7 +594,7 @@ class Helpers:
|
||||
pid = data.get("pid")
|
||||
started = data.get("started")
|
||||
if psutil.pid_exists(pid):
|
||||
console.critical(
|
||||
Console.critical(
|
||||
f"Another Crafty Controller agent seems to be running..."
|
||||
f"\npid: {pid} \nstarted on: {started}"
|
||||
)
|
||||
@ -555,7 +609,7 @@ class Helpers:
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to locate existing session.lock with error: {e} ")
|
||||
console.error(
|
||||
Console.error(
|
||||
f"Failed to locate existing session.lock with error: {e} "
|
||||
)
|
||||
|
||||
@ -570,11 +624,12 @@ class Helpers:
|
||||
|
||||
# because this is a recursive function, we will return bytes,
|
||||
# and set human readable later
|
||||
def get_dir_size(self, path: str):
|
||||
@staticmethod
|
||||
def get_dir_size(path: str):
|
||||
total = 0
|
||||
for entry in os.scandir(path):
|
||||
if entry.is_dir(follow_symlinks=False):
|
||||
total += self.get_dir_size(entry.path)
|
||||
total += Helpers.get_dir_size(entry.path)
|
||||
else:
|
||||
total += entry.stat(follow_symlinks=False).st_size
|
||||
return total
|
||||
@ -588,11 +643,15 @@ class Helpers:
|
||||
)
|
||||
]
|
||||
|
||||
def get_human_readable_files_sizes(self, paths: list):
|
||||
@staticmethod
|
||||
def get_human_readable_files_sizes(paths: list):
|
||||
sizes = []
|
||||
for p in paths:
|
||||
sizes.append(
|
||||
{"path": p, "size": self.human_readable_file_size(os.stat(p).st_size)}
|
||||
{
|
||||
"path": p,
|
||||
"size": Helpers.human_readable_file_size(os.stat(p).st_size),
|
||||
}
|
||||
)
|
||||
return sizes
|
||||
|
||||
@ -608,10 +667,12 @@ class Helpers:
|
||||
b64_bytes = base64.decodebytes(s_bytes)
|
||||
return b64_bytes.decode("utf-8")
|
||||
|
||||
def create_uuid(self):
|
||||
@staticmethod
|
||||
def create_uuid():
|
||||
return str(uuid.uuid4())
|
||||
|
||||
def ensure_dir_exists(self, path):
|
||||
@staticmethod
|
||||
def ensure_dir_exists(path):
|
||||
"""
|
||||
ensures a directory exists
|
||||
|
||||
@ -637,7 +698,7 @@ class Helpers:
|
||||
cert_dir = os.path.join(self.config_dir, "web", "certs")
|
||||
|
||||
# create a directory if needed
|
||||
self.ensure_dir_exists(cert_dir)
|
||||
Helpers.ensure_dir_exists(cert_dir)
|
||||
|
||||
cert_file = os.path.join(cert_dir, "commander.cert.pem")
|
||||
key_file = os.path.join(cert_dir, "commander.key.pem")
|
||||
@ -646,16 +707,16 @@ class Helpers:
|
||||
logger.info(f"SSL Key File is set to: {key_file}")
|
||||
|
||||
# don't create new files if we already have them.
|
||||
if self.check_file_exists(cert_file) and self.check_file_exists(key_file):
|
||||
if Helpers.check_file_exists(cert_file) and Helpers.check_file_exists(key_file):
|
||||
logger.info("Cert and Key files already exists, not creating them.")
|
||||
return True
|
||||
|
||||
console.info("Generating a self signed SSL")
|
||||
Console.info("Generating a self signed SSL")
|
||||
logger.info("Generating a self signed SSL")
|
||||
|
||||
# create a key pair
|
||||
logger.info("Generating a key pair. This might take a moment.")
|
||||
console.info("Generating a key pair. This might take a moment.")
|
||||
Console.info("Generating a key pair. This might take a moment.")
|
||||
k = crypto.PKey()
|
||||
k.generate_key(crypto.TYPE_RSA, 4096)
|
||||
|
||||
@ -676,11 +737,13 @@ class Helpers:
|
||||
"DNS:127.0.0.1",
|
||||
]
|
||||
).encode()
|
||||
subjectAltNames_Ext = crypto.X509Extension(b"subjectAltName", False, alt_names)
|
||||
basicConstraints_Ext = crypto.X509Extension(
|
||||
subject_alt_names_ext = crypto.X509Extension(
|
||||
b"subjectAltName", False, alt_names
|
||||
)
|
||||
basic_constraints_ext = crypto.X509Extension(
|
||||
b"basicConstraints", True, b"CA:false"
|
||||
)
|
||||
cert.add_extensions([subjectAltNames_Ext, basicConstraints_Ext])
|
||||
cert.add_extensions([subject_alt_names_ext, basic_constraints_ext])
|
||||
cert.set_serial_number(random.randint(1, 255))
|
||||
cert.gmtime_adj_notBefore(0)
|
||||
cert.gmtime_adj_notAfter(365 * 24 * 60 * 60)
|
||||
@ -731,11 +794,11 @@ class Helpers:
|
||||
default_file = os.path.join(self.root_dir, "default.json")
|
||||
data = {}
|
||||
|
||||
if self.check_file_exists(default_file):
|
||||
if Helpers.check_file_exists(default_file):
|
||||
with open(default_file, "r", encoding="utf-8") as f:
|
||||
data = json.load(f)
|
||||
|
||||
del_json = helper.get_setting("delete_default_json")
|
||||
del_json = self.get_setting("delete_default_json")
|
||||
|
||||
if del_json:
|
||||
os.remove(default_file)
|
||||
@ -763,8 +826,8 @@ class Helpers:
|
||||
output += f"""<li class="tree-item" data-path="{dpath}">
|
||||
\n<div id="{dpath}" data-path="{dpath}" data-name="{filename}" class="tree-caret tree-ctx-item tree-folder">
|
||||
<span id="{dpath}span" class="files-tree-title" data-path="{dpath}" data-name="{filename}" onclick="getDirView(event)">
|
||||
<i class="far fa-folder"></i>
|
||||
<i class="far fa-folder-open"></i>
|
||||
<i style="color: #8862e0;" class="far fa-folder"></i>
|
||||
<i style="color: #8862e0;" class="far fa-folder-open"></i>
|
||||
{filename}
|
||||
</span>
|
||||
</div><li>
|
||||
@ -772,7 +835,7 @@ class Helpers:
|
||||
else:
|
||||
if filename != "crafty_managed.txt":
|
||||
output += f"""<li
|
||||
class="tree-nested d-block tree-ctx-item tree-file tree-item"
|
||||
class="d-block tree-ctx-item tree-file tree-item"
|
||||
data-path="{dpath}"
|
||||
data-name="{filename}"
|
||||
onclick="clickOnFile(event)"><span style="margin-right: 6px;">
|
||||
@ -801,15 +864,15 @@ class Helpers:
|
||||
output += f"""<li class="tree-item" data-path="{dpath}">
|
||||
\n<div id="{dpath}" data-path="{dpath}" data-name="{filename}" class="tree-caret tree-ctx-item tree-folder">
|
||||
<span id="{dpath}span" class="files-tree-title" data-path="{dpath}" data-name="{filename}" onclick="getDirView(event)">
|
||||
<i class="far fa-folder"></i>
|
||||
<i class="far fa-folder-open"></i>
|
||||
<i style="color: #8862e0;" class="far fa-folder"></i>
|
||||
<i style="color: #8862e0;" class="far fa-folder-open"></i>
|
||||
{filename}
|
||||
</span>
|
||||
</div><li>"""
|
||||
else:
|
||||
if filename != "crafty_managed.txt":
|
||||
output += f"""<li
|
||||
class="tree-nested d-block tree-ctx-item tree-file tree-item"
|
||||
class="d-block tree-ctx-item tree-file tree-item"
|
||||
data-path="{dpath}"
|
||||
data-name="{filename}"
|
||||
onclick="clickOnFile(event)"><span style="margin-right: 6px;">
|
||||
@ -831,8 +894,8 @@ class Helpers:
|
||||
\n<div id="{dpath}" data-path="{dpath}" data-name="{filename}" class="tree-caret tree-ctx-item tree-folder">
|
||||
<input type="radio" name="root_path" value="{dpath}">
|
||||
<span id="{dpath}span" class="files-tree-title" data-path="{dpath}" data-name="{filename}" onclick="getDirView(event)">
|
||||
<i class="far fa-folder"></i>
|
||||
<i class="far fa-folder-open"></i>
|
||||
<i style="color: #8862e0;" class="far fa-folder"></i>
|
||||
<i style="color: #8862e0;" class="far fa-folder-open"></i>
|
||||
{filename}
|
||||
</span>
|
||||
</input></div><li>
|
||||
@ -853,39 +916,39 @@ class Helpers:
|
||||
\n<div id="{dpath}" data-path="{dpath}" data-name="{filename}" class="tree-caret tree-ctx-item tree-folder">
|
||||
<input type="radio" name="root_path" value="{dpath}">
|
||||
<span id="{dpath}span" class="files-tree-title" data-path="{dpath}" data-name="{filename}" onclick="getDirView(event)">
|
||||
<i class="far fa-folder"></i>
|
||||
<i class="far fa-folder-open"></i>
|
||||
<i style="color: #8862e0;" class="far fa-folder"></i>
|
||||
<i style="color: #8862e0;" class="far fa-folder-open"></i>
|
||||
{filename}
|
||||
</span>
|
||||
</input></div><li>"""
|
||||
return output
|
||||
|
||||
@staticmethod
|
||||
def unzipServer(zip_path, user_id):
|
||||
if helper.check_file_perms(zip_path):
|
||||
tempDir = tempfile.mkdtemp()
|
||||
def unzip_server(self, zip_path, user_id):
|
||||
if Helpers.check_file_perms(zip_path):
|
||||
temp_dir = tempfile.mkdtemp()
|
||||
with zipfile.ZipFile(zip_path, "r") as zip_ref:
|
||||
# extracts archive to temp directory
|
||||
zip_ref.extractall(tempDir)
|
||||
zip_ref.extractall(temp_dir)
|
||||
if user_id:
|
||||
websocket_helper.broadcast_user(
|
||||
user_id, "send_temp_path", {"path": tempDir}
|
||||
self.websocket_helper.broadcast_user(
|
||||
user_id, "send_temp_path", {"path": temp_dir}
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def backup_select(path, user_id):
|
||||
def backup_select(self, path, user_id):
|
||||
if user_id:
|
||||
websocket_helper.broadcast_user(user_id, "send_temp_path", {"path": path})
|
||||
self.websocket_helper.broadcast_user(
|
||||
user_id, "send_temp_path", {"path": path}
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def unzip_backup_archive(backup_path, zip_name):
|
||||
zip_path = os.path.join(backup_path, zip_name)
|
||||
if helper.check_file_perms(zip_path):
|
||||
tempDir = tempfile.mkdtemp()
|
||||
if Helpers.check_file_perms(zip_path):
|
||||
temp_dir = tempfile.mkdtemp()
|
||||
with zipfile.ZipFile(zip_path, "r") as zip_ref:
|
||||
# extracts archive to temp directory
|
||||
zip_ref.extractall(tempDir)
|
||||
return tempDir
|
||||
zip_ref.extractall(temp_dir)
|
||||
return temp_dir
|
||||
else:
|
||||
return False
|
||||
|
||||
@ -905,14 +968,10 @@ class Helpers:
|
||||
[parent_path, child_path]
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def in_path_old(x, y):
|
||||
return os.path.abspath(y).__contains__(os.path.abspath(x))
|
||||
|
||||
@staticmethod
|
||||
def copy_files(source, dest):
|
||||
if os.path.isfile(source):
|
||||
file_helper.copy_file(source, dest)
|
||||
FileHelpers.copy_file(source, dest)
|
||||
logger.info("Copying jar %s to %s", source, dest)
|
||||
else:
|
||||
logger.info("Source jar does not exist.")
|
||||
@ -920,16 +979,16 @@ class Helpers:
|
||||
@staticmethod
|
||||
def download_file(executable_url, jar_path):
|
||||
try:
|
||||
r = requests.get(executable_url, timeout=5)
|
||||
response = requests.get(executable_url, timeout=5)
|
||||
except Exception as ex:
|
||||
logger.error("Could not download executable: %s", ex)
|
||||
return False
|
||||
if r.status_code != 200:
|
||||
if response.status_code != 200:
|
||||
logger.error("Unable to download file from %s", executable_url)
|
||||
return False
|
||||
|
||||
try:
|
||||
open(jar_path, "wb").write(r.content)
|
||||
open(jar_path, "wb").write(response.content)
|
||||
except Exception as e:
|
||||
logger.error("Unable to finish executable download. Error: %s", e)
|
||||
return False
|
||||
@ -942,13 +1001,10 @@ class Helpers:
|
||||
return text
|
||||
|
||||
@staticmethod
|
||||
def getLangPage(text):
|
||||
def get_lang_page(text):
|
||||
lang = text.split("_")[0]
|
||||
region = text.split("_")[1]
|
||||
if region == "EN":
|
||||
return "en"
|
||||
else:
|
||||
return lang + "-" + region
|
||||
|
||||
|
||||
helper = Helpers()
|
||||
|
@ -2,16 +2,16 @@ import json
|
||||
import os
|
||||
import logging
|
||||
|
||||
from app.classes.controllers.users_controller import users_helper
|
||||
from app.classes.shared.main_controller import Controller
|
||||
from app.classes.shared.console import console
|
||||
from app.classes.controllers.users_controller import HelperUsers
|
||||
from app.classes.shared.console import Console
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class import3:
|
||||
def __init__(self):
|
||||
self.controller = Controller()
|
||||
class Import3:
|
||||
def __init__(self, helper, controller):
|
||||
self.helper = helper
|
||||
self.controller = controller
|
||||
|
||||
def start_import(self):
|
||||
folder = os.path.normpath(
|
||||
@ -21,11 +21,11 @@ class import3:
|
||||
)
|
||||
)
|
||||
if not os.path.exists(folder):
|
||||
console.info(
|
||||
Console.info(
|
||||
"Crafty cannot find the path you entered. "
|
||||
"Does Crafty's user have permission to access it?"
|
||||
)
|
||||
console.info("Please run the import3 command again and enter a valid path.")
|
||||
Console.info("Please run the import3 command again and enter a valid path.")
|
||||
else:
|
||||
with open(os.path.join(folder, "users.json"), encoding="utf-8") as f:
|
||||
user_json = json.loads(f.read())
|
||||
@ -34,16 +34,15 @@ class import3:
|
||||
self.import_users(user_json)
|
||||
self.import_servers(servers_json, self.controller)
|
||||
|
||||
@staticmethod
|
||||
def import_users(json_data):
|
||||
def import_users(self, json_data):
|
||||
# If there is only one user to import json needs to call the data differently
|
||||
if isinstance(json_data, list):
|
||||
for user in json_data:
|
||||
users_helper.add_rawpass_user(user["username"], user["password"])
|
||||
console.info(f"Imported user {user['username']} from Crafty 3")
|
||||
HelperUsers.add_rawpass_user(user["username"], user["password"])
|
||||
Console.info(f"Imported user {user['username']} from Crafty 3")
|
||||
logger.info(f"Imported user {user['username']} from Crafty 3")
|
||||
else:
|
||||
console.info(
|
||||
Console.info(
|
||||
"There is only one user detected. "
|
||||
"Cannot create duplicate Admin account."
|
||||
)
|
||||
@ -52,8 +51,7 @@ class import3:
|
||||
"Cannot create duplicate Admin account."
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def import_servers(json_data, controller):
|
||||
def import_servers(self, json_data, controller):
|
||||
# If there is only one server to import json needs to call the data differently
|
||||
if isinstance(json_data, list):
|
||||
for server in json_data:
|
||||
@ -65,7 +63,7 @@ class import3:
|
||||
max_mem=(int(server["memory_max"]) / 1000),
|
||||
port=server["server_port"],
|
||||
)
|
||||
console.info(
|
||||
Console.info(
|
||||
f"Imported server {server['server_name']}[{server['id']}] "
|
||||
f"from Crafty 3 to new server id {new_server_id}"
|
||||
)
|
||||
@ -82,7 +80,7 @@ class import3:
|
||||
max_mem=(int(json_data["memory_max"]) / 1000),
|
||||
port=json_data["server_port"],
|
||||
)
|
||||
console.info(
|
||||
Console.info(
|
||||
f"Imported server {json_data['server_name']}[{json_data['id']}] "
|
||||
f"from Crafty 3 to new server id {new_server_id}"
|
||||
)
|
||||
@ -90,6 +88,3 @@ class import3:
|
||||
f"Imported server {json_data['server_name']}[{json_data['id']}] "
|
||||
f"from Crafty 3 to new server id {new_server_id}"
|
||||
)
|
||||
|
||||
|
||||
import3 = import3()
|
||||
|
@ -2,7 +2,7 @@ import sys
|
||||
import subprocess
|
||||
|
||||
|
||||
class install:
|
||||
class Install:
|
||||
@staticmethod
|
||||
def is_venv():
|
||||
return hasattr(sys, "real_prefix") or (
|
||||
@ -24,4 +24,4 @@ class install:
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
installer = install()
|
||||
installer = Install()
|
||||
|
@ -6,49 +6,54 @@ import time
|
||||
import logging
|
||||
import tempfile
|
||||
from typing import Union
|
||||
from peewee import DoesNotExist
|
||||
|
||||
from app.classes.controllers.crafty_perms_controller import Crafty_Perms_Controller
|
||||
from app.classes.controllers.management_controller import Management_Controller
|
||||
from app.classes.controllers.users_controller import Users_Controller
|
||||
from app.classes.controllers.roles_controller import Roles_Controller
|
||||
from app.classes.controllers.server_perms_controller import Server_Perms_Controller
|
||||
from app.classes.controllers.servers_controller import Servers_Controller
|
||||
from app.classes.models.server_permissions import Enum_Permissions_Server
|
||||
from app.classes.models.users import helper_users
|
||||
from app.classes.models.management import helpers_management
|
||||
from app.classes.models.servers import servers_helper
|
||||
from app.classes.shared.console import console
|
||||
from app.classes.shared.helpers import helper
|
||||
# TZLocal is set as a hidden import on win pipeline
|
||||
from tzlocal import get_localzone
|
||||
from apscheduler.schedulers.background import BackgroundScheduler
|
||||
|
||||
from app.classes.controllers.crafty_perms_controller import CraftyPermsController
|
||||
from app.classes.controllers.management_controller import ManagementController
|
||||
from app.classes.controllers.users_controller import UsersController
|
||||
from app.classes.controllers.roles_controller import RolesController
|
||||
from app.classes.controllers.server_perms_controller import ServerPermsController
|
||||
from app.classes.controllers.servers_controller import ServersController
|
||||
from app.classes.models.server_permissions import EnumPermissionsServer
|
||||
from app.classes.models.users import HelperUsers
|
||||
from app.classes.models.roles import HelperRoles
|
||||
from app.classes.models.management import HelpersManagement
|
||||
from app.classes.models.servers import HelperServers
|
||||
from app.classes.shared.authentication import Authentication
|
||||
from app.classes.shared.console import Console
|
||||
from app.classes.shared.helpers import Helpers
|
||||
from app.classes.shared.server import Server
|
||||
from app.classes.shared.file_helpers import file_helper
|
||||
from app.classes.shared.file_helpers import FileHelpers
|
||||
from app.classes.minecraft.server_props import ServerProps
|
||||
from app.classes.minecraft.serverjars import server_jar_obj
|
||||
from app.classes.minecraft.serverjars import ServerJars
|
||||
from app.classes.minecraft.stats import Stats
|
||||
from app.classes.web.websocket_helper import websocket_helper
|
||||
|
||||
try:
|
||||
from peewee import DoesNotExist
|
||||
|
||||
# TZLocal is set as a hidden import on win pipeline
|
||||
from tzlocal import get_localzone
|
||||
from apscheduler.schedulers.background import BackgroundScheduler
|
||||
|
||||
except ModuleNotFoundError as err:
|
||||
helper.auto_installer_fix(err)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Controller:
|
||||
def __init__(self):
|
||||
def __init__(self, database, helper):
|
||||
self.helper = helper
|
||||
self.server_jars = ServerJars(helper)
|
||||
self.users_helper = HelperUsers(database, self.helper)
|
||||
self.roles_helper = HelperRoles(database)
|
||||
self.servers_helper = HelperServers(database)
|
||||
self.management_helper = HelpersManagement(database, self.helper)
|
||||
self.authentication = Authentication(self.helper)
|
||||
self.servers_list = []
|
||||
self.stats = Stats(self)
|
||||
self.crafty_perms = Crafty_Perms_Controller()
|
||||
self.management = Management_Controller()
|
||||
self.roles = Roles_Controller()
|
||||
self.server_perms = Server_Perms_Controller()
|
||||
self.servers = Servers_Controller()
|
||||
self.users = Users_Controller()
|
||||
self.stats = Stats(self.helper, self)
|
||||
self.crafty_perms = CraftyPermsController()
|
||||
self.management = ManagementController(self.management_helper)
|
||||
self.roles = RolesController(self.users_helper, self.roles_helper)
|
||||
self.server_perms = ServerPermsController()
|
||||
self.servers = ServersController(self.servers_helper)
|
||||
self.users = UsersController(
|
||||
self.helper, self.users_helper, self.authentication
|
||||
)
|
||||
tz = get_localzone()
|
||||
self.support_scheduler = BackgroundScheduler(timezone=str(tz))
|
||||
self.support_scheduler.start()
|
||||
@ -57,8 +62,8 @@ class Controller:
|
||||
|
||||
logger.info(f"Checking to see if we already registered {server_id_to_check}")
|
||||
|
||||
for s in self.servers_list:
|
||||
known_server = s.get("server_id")
|
||||
for server in self.servers_list:
|
||||
known_server = server.get("server_id")
|
||||
if known_server is None:
|
||||
return False
|
||||
|
||||
@ -75,63 +80,65 @@ class Controller:
|
||||
|
||||
servers = self.servers.get_all_defined_servers()
|
||||
|
||||
for s in servers:
|
||||
server_id = s.get("server_id")
|
||||
for server in servers:
|
||||
server_id = server.get("server_id")
|
||||
|
||||
# if we have already initialized this server, let's skip it.
|
||||
if self.check_server_loaded(server_id):
|
||||
continue
|
||||
|
||||
# if this server path no longer exists - let's warn and bomb out
|
||||
if not helper.check_path_exists(
|
||||
helper.get_os_understandable_path(s["path"])
|
||||
if not Helpers.check_path_exists(
|
||||
Helpers.get_os_understandable_path(server["path"])
|
||||
):
|
||||
logger.warning(
|
||||
f"Unable to find server {s['server_name']} at path {s['path']}. "
|
||||
f"Unable to find server "
|
||||
f"{server['server_name']} at path {server['path']}. "
|
||||
f"Skipping this server"
|
||||
)
|
||||
|
||||
console.warning(
|
||||
f"Unable to find server {s['server_name']} at path {s['path']}. "
|
||||
Console.warning(
|
||||
f"Unable to find server "
|
||||
f"{server['server_name']} at path {server['path']}. "
|
||||
f"Skipping this server"
|
||||
)
|
||||
continue
|
||||
|
||||
settings_file = os.path.join(
|
||||
helper.get_os_understandable_path(s["path"]), "server.properties"
|
||||
Helpers.get_os_understandable_path(server["path"]), "server.properties"
|
||||
)
|
||||
|
||||
# if the properties file isn't there, let's warn
|
||||
if not helper.check_file_exists(settings_file):
|
||||
if not Helpers.check_file_exists(settings_file):
|
||||
logger.error(f"Unable to find {settings_file}. Skipping this server.")
|
||||
console.error(f"Unable to find {settings_file}. Skipping this server.")
|
||||
Console.error(f"Unable to find {settings_file}. Skipping this server.")
|
||||
continue
|
||||
|
||||
settings = ServerProps(settings_file)
|
||||
|
||||
temp_server_dict = {
|
||||
"server_id": s.get("server_id"),
|
||||
"server_data_obj": s,
|
||||
"server_obj": Server(self.stats),
|
||||
"server_id": server.get("server_id"),
|
||||
"server_data_obj": server,
|
||||
"server_obj": Server(self.helper, self.management_helper, self.stats),
|
||||
"server_settings": settings.props,
|
||||
}
|
||||
|
||||
# setup the server, do the auto start and all that jazz
|
||||
temp_server_dict["server_obj"].do_server_setup(s)
|
||||
temp_server_dict["server_obj"].do_server_setup(server)
|
||||
|
||||
# add this temp object to the list of init servers
|
||||
self.servers_list.append(temp_server_dict)
|
||||
|
||||
if s["auto_start"]:
|
||||
self.servers.set_waiting_start(s["server_id"], True)
|
||||
if server["auto_start"]:
|
||||
self.servers.set_waiting_start(server["server_id"], True)
|
||||
|
||||
self.refresh_server_settings(s["server_id"])
|
||||
self.refresh_server_settings(server["server_id"])
|
||||
|
||||
console.info(
|
||||
f"Loaded Server: ID {s['server_id']}"
|
||||
+ f" | Name: {s['server_name']}"
|
||||
+ f" | Autostart: {s['auto_start']}"
|
||||
+ f" | Delay: {s['auto_start_delay']} "
|
||||
Console.info(
|
||||
f"Loaded Server: ID {server['server_id']}"
|
||||
f" | Name: {server['server_name']}"
|
||||
f" | Autostart: {server['auto_start']}"
|
||||
f" | Delay: {server['auto_start_delay']}"
|
||||
)
|
||||
|
||||
def refresh_server_settings(self, server_id: int):
|
||||
@ -140,7 +147,7 @@ class Controller:
|
||||
|
||||
@staticmethod
|
||||
def check_system_user():
|
||||
if helper_users.get_user_id_by_name("system") is not None:
|
||||
if HelperUsers.get_user_id_by_name("system") is not None:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
@ -154,14 +161,14 @@ class Controller:
|
||||
self.users.set_prepare(exec_user["user_id"])
|
||||
# pausing so on screen notifications can run for user
|
||||
time.sleep(7)
|
||||
websocket_helper.broadcast_user(
|
||||
self.helper.websocket_helper.broadcast_user(
|
||||
exec_user["user_id"], "notification", "Preparing your support logs"
|
||||
)
|
||||
tempDir = tempfile.mkdtemp()
|
||||
tempZipStorage = tempfile.mkdtemp()
|
||||
full_temp = os.path.join(tempDir, "support_logs")
|
||||
temp_dir = tempfile.mkdtemp()
|
||||
temp_zip_storage = tempfile.mkdtemp()
|
||||
full_temp = os.path.join(temp_dir, "support_logs")
|
||||
os.mkdir(full_temp)
|
||||
tempZipStorage = os.path.join(tempZipStorage, "support_logs")
|
||||
temp_zip_storage = os.path.join(temp_zip_storage, "support_logs")
|
||||
crafty_path = os.path.join(full_temp, "crafty")
|
||||
os.mkdir(crafty_path)
|
||||
server_path = os.path.join(full_temp, "server")
|
||||
@ -175,7 +182,7 @@ class Controller:
|
||||
auth_servers = []
|
||||
for server in user_servers:
|
||||
if (
|
||||
Enum_Permissions_Server.Logs
|
||||
EnumPermissionsServer.LOGS
|
||||
in self.server_perms.get_user_id_permissions_list(
|
||||
exec_user["user_id"], server["server_id"]
|
||||
)
|
||||
@ -195,50 +202,51 @@ class Controller:
|
||||
final_path += "_" + server["server_uuid"]
|
||||
os.mkdir(final_path)
|
||||
try:
|
||||
file_helper.copy_file(server["log_path"], final_path)
|
||||
FileHelpers.copy_file(server["log_path"], final_path)
|
||||
except Exception as e:
|
||||
logger.warning(f"Failed to copy file with error: {e}")
|
||||
# Copy crafty logs to archive dir
|
||||
full_log_name = os.path.join(crafty_path, "logs")
|
||||
file_helper.copy_dir(os.path.join(self.project_root, "logs"), full_log_name)
|
||||
FileHelpers.copy_dir(os.path.join(self.project_root, "logs"), full_log_name)
|
||||
self.support_scheduler.add_job(
|
||||
self.log_status,
|
||||
"interval",
|
||||
seconds=1,
|
||||
id="logs_" + str(exec_user["user_id"]),
|
||||
args=[full_temp, tempZipStorage + ".zip", exec_user],
|
||||
args=[full_temp, temp_zip_storage + ".zip", exec_user],
|
||||
)
|
||||
file_helper.make_archive(tempZipStorage, tempDir)
|
||||
FileHelpers.make_archive(temp_zip_storage, temp_dir)
|
||||
|
||||
if len(websocket_helper.clients) > 0:
|
||||
websocket_helper.broadcast_user(
|
||||
if len(self.helper.websocket_helper.clients) > 0:
|
||||
self.helper.websocket_helper.broadcast_user(
|
||||
exec_user["user_id"],
|
||||
"support_status_update",
|
||||
helper.calc_percent(full_temp, tempZipStorage + ".zip"),
|
||||
Helpers.calc_percent(full_temp, temp_zip_storage + ".zip"),
|
||||
)
|
||||
|
||||
tempZipStorage += ".zip"
|
||||
websocket_helper.broadcast_user(exec_user["user_id"], "send_logs_bootbox", {})
|
||||
temp_zip_storage += ".zip"
|
||||
self.helper.websocket_helper.broadcast_user(
|
||||
exec_user["user_id"], "send_logs_bootbox", {}
|
||||
)
|
||||
|
||||
self.users.set_support_path(exec_user["user_id"], tempZipStorage)
|
||||
self.users.set_support_path(exec_user["user_id"], temp_zip_storage)
|
||||
|
||||
self.users.stop_prepare(exec_user["user_id"])
|
||||
self.support_scheduler.remove_job("logs_" + str(exec_user["user_id"]))
|
||||
|
||||
@staticmethod
|
||||
def add_system_user():
|
||||
helper_users.add_user(
|
||||
def add_system_user(self):
|
||||
self.users_helper.add_user(
|
||||
"system",
|
||||
helper.random_string_generator(64),
|
||||
Helpers.random_string_generator(64),
|
||||
"default@example.com",
|
||||
False,
|
||||
False,
|
||||
)
|
||||
|
||||
def get_server_settings(self, server_id):
|
||||
for s in self.servers_list:
|
||||
if int(s["server_id"]) == int(server_id):
|
||||
return s["server_settings"]
|
||||
for server in self.servers_list:
|
||||
if int(server["server_id"]) == int(server_id):
|
||||
return server["server_settings"]
|
||||
|
||||
logger.warning(f"Unable to find server object for server id {server_id}")
|
||||
return False
|
||||
@ -254,11 +262,11 @@ class Controller:
|
||||
svr.stop_crash_detection()
|
||||
|
||||
def log_status(self, source_path, dest_path, exec_user):
|
||||
results = helper.calc_percent(source_path, dest_path)
|
||||
results = Helpers.calc_percent(source_path, dest_path)
|
||||
self.log_stats = results
|
||||
|
||||
if len(websocket_helper.clients) > 0:
|
||||
websocket_helper.broadcast_user(
|
||||
if len(self.helper.websocket_helper.clients) > 0:
|
||||
self.helper.websocket_helper.broadcast_user(
|
||||
exec_user["user_id"], "support_status_update", results
|
||||
)
|
||||
|
||||
@ -269,34 +277,34 @@ class Controller:
|
||||
return {"percent": 0, "total_files": 0}
|
||||
|
||||
def get_server_obj(self, server_id: Union[str, int]) -> Union[bool, Server]:
|
||||
for s in self.servers_list:
|
||||
if str(s["server_id"]) == str(server_id):
|
||||
return s["server_obj"]
|
||||
for server in self.servers_list:
|
||||
if str(server["server_id"]) == str(server_id):
|
||||
return server["server_obj"]
|
||||
|
||||
logger.warning(f"Unable to find server object for server id {server_id}")
|
||||
return False # TODO: Change to None
|
||||
|
||||
def get_server_data(self, server_id: str):
|
||||
for s in self.servers_list:
|
||||
if str(s["server_id"]) == str(server_id):
|
||||
return s["server_data_obj"]
|
||||
for server in self.servers_list:
|
||||
if str(server["server_id"]) == str(server_id):
|
||||
return server["server_data_obj"]
|
||||
|
||||
logger.warning(f"Unable to find server object for server id {server_id}")
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def list_defined_servers():
|
||||
servers = servers_helper.get_all_defined_servers()
|
||||
servers = HelperServers.get_all_defined_servers()
|
||||
return servers
|
||||
|
||||
def list_running_servers(self):
|
||||
running_servers = []
|
||||
|
||||
# for each server
|
||||
for s in self.servers_list:
|
||||
for servers in self.servers_list:
|
||||
|
||||
# is the server running?
|
||||
srv_obj = s["server_obj"]
|
||||
srv_obj = servers["server_obj"]
|
||||
running = srv_obj.check_running()
|
||||
# if so, let's add a dictionary to the list of running servers
|
||||
if running:
|
||||
@ -307,22 +315,22 @@ class Controller:
|
||||
def stop_all_servers(self):
|
||||
servers = self.list_running_servers()
|
||||
logger.info(f"Found {len(servers)} running server(s)")
|
||||
console.info(f"Found {len(servers)} running server(s)")
|
||||
Console.info(f"Found {len(servers)} running server(s)")
|
||||
|
||||
logger.info("Stopping All Servers")
|
||||
console.info("Stopping All Servers")
|
||||
Console.info("Stopping All Servers")
|
||||
|
||||
for s in servers:
|
||||
logger.info(f"Stopping Server ID {s['id']} - {s['name']}")
|
||||
console.info(f"Stopping Server ID {s['id']} - {s['name']}")
|
||||
for server in servers:
|
||||
logger.info(f"Stopping Server ID {server['id']} - {server['name']}")
|
||||
Console.info(f"Stopping Server ID {server['id']} - {server['name']}")
|
||||
|
||||
self.stop_server(s["id"])
|
||||
self.stop_server(server["id"])
|
||||
|
||||
# let's wait 2 seconds to let everything flush out
|
||||
time.sleep(2)
|
||||
|
||||
logger.info("All Servers Stopped")
|
||||
console.info("All Servers Stopped")
|
||||
Console.info("All Servers Stopped")
|
||||
|
||||
def stop_server(self, server_id):
|
||||
# issue the stop command
|
||||
@ -338,12 +346,12 @@ class Controller:
|
||||
max_mem: int,
|
||||
port: int,
|
||||
):
|
||||
server_id = helper.create_uuid()
|
||||
server_dir = os.path.join(helper.servers_dir, server_id)
|
||||
backup_path = os.path.join(helper.backup_path, server_id)
|
||||
if helper.is_os_windows():
|
||||
server_dir = helper.wtol_path(server_dir)
|
||||
backup_path = helper.wtol_path(backup_path)
|
||||
server_id = Helpers.create_uuid()
|
||||
server_dir = os.path.join(self.helper.servers_dir, server_id)
|
||||
backup_path = os.path.join(self.helper.backup_path, server_id)
|
||||
if Helpers.is_os_windows():
|
||||
server_dir = Helpers.wtol_path(server_dir)
|
||||
backup_path = Helpers.wtol_path(backup_path)
|
||||
server_dir.replace(" ", "^ ")
|
||||
backup_path.replace(" ", "^ ")
|
||||
|
||||
@ -351,36 +359,38 @@ class Controller:
|
||||
full_jar_path = os.path.join(server_dir, server_file)
|
||||
|
||||
# make the dir - perhaps a UUID?
|
||||
helper.ensure_dir_exists(server_dir)
|
||||
helper.ensure_dir_exists(backup_path)
|
||||
Helpers.ensure_dir_exists(server_dir)
|
||||
Helpers.ensure_dir_exists(backup_path)
|
||||
|
||||
try:
|
||||
# do a eula.txt
|
||||
with open(os.path.join(server_dir, "eula.txt"), "w", encoding="utf-8") as f:
|
||||
f.write("eula=false")
|
||||
f.close()
|
||||
with open(
|
||||
os.path.join(server_dir, "eula.txt"), "w", encoding="utf-8"
|
||||
) as file:
|
||||
file.write("eula=false")
|
||||
file.close()
|
||||
|
||||
# setup server.properties with the port
|
||||
with open(
|
||||
os.path.join(server_dir, "server.properties"), "w", encoding="utf-8"
|
||||
) as f:
|
||||
f.write(f"server-port={port}")
|
||||
f.close()
|
||||
) as file:
|
||||
file.write(f"server-port={port}")
|
||||
file.close()
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Unable to create required server files due to :{e}")
|
||||
return False
|
||||
|
||||
if helper.is_os_windows():
|
||||
if Helpers.is_os_windows():
|
||||
server_command = (
|
||||
f"java -Xms{helper.float_to_string(min_mem)}M "
|
||||
f"-Xmx{helper.float_to_string(max_mem)}M "
|
||||
f"java -Xms{Helpers.float_to_string(min_mem)}M "
|
||||
f"-Xmx{Helpers.float_to_string(max_mem)}M "
|
||||
f'-jar "{full_jar_path}" nogui'
|
||||
)
|
||||
else:
|
||||
server_command = (
|
||||
f"java -Xms{helper.float_to_string(min_mem)}M "
|
||||
f"-Xmx{helper.float_to_string(max_mem)}M "
|
||||
f"java -Xms{Helpers.float_to_string(min_mem)}M "
|
||||
f"-Xmx{Helpers.float_to_string(max_mem)}M "
|
||||
f"-jar {full_jar_path} nogui"
|
||||
)
|
||||
server_log_file = f"{server_dir}/logs/latest.log"
|
||||
@ -400,23 +410,23 @@ class Controller:
|
||||
)
|
||||
|
||||
# download the jar
|
||||
server_jar_obj.download_jar(server, version, full_jar_path, new_id)
|
||||
self.server_jars.download_jar(server, version, full_jar_path, new_id)
|
||||
|
||||
return new_id
|
||||
|
||||
@staticmethod
|
||||
def verify_jar_server(server_path: str, server_jar: str):
|
||||
server_path = helper.get_os_understandable_path(server_path)
|
||||
path_check = helper.check_path_exists(server_path)
|
||||
jar_check = helper.check_file_exists(os.path.join(server_path, server_jar))
|
||||
server_path = Helpers.get_os_understandable_path(server_path)
|
||||
path_check = Helpers.check_path_exists(server_path)
|
||||
jar_check = Helpers.check_file_exists(os.path.join(server_path, server_jar))
|
||||
if not path_check or not jar_check:
|
||||
return False
|
||||
return True
|
||||
|
||||
@staticmethod
|
||||
def verify_zip_server(zip_path: str):
|
||||
zip_path = helper.get_os_understandable_path(zip_path)
|
||||
zip_check = helper.check_file_exists(zip_path)
|
||||
zip_path = Helpers.get_os_understandable_path(zip_path)
|
||||
zip_check = Helpers.check_file_exists(zip_path)
|
||||
if not zip_check:
|
||||
return False
|
||||
return True
|
||||
@ -430,20 +440,20 @@ class Controller:
|
||||
max_mem: int,
|
||||
port: int,
|
||||
):
|
||||
server_id = helper.create_uuid()
|
||||
new_server_dir = os.path.join(helper.servers_dir, server_id)
|
||||
backup_path = os.path.join(helper.backup_path, server_id)
|
||||
if helper.is_os_windows():
|
||||
new_server_dir = helper.wtol_path(new_server_dir)
|
||||
backup_path = helper.wtol_path(backup_path)
|
||||
server_id = Helpers.create_uuid()
|
||||
new_server_dir = os.path.join(self.helper.servers_dir, server_id)
|
||||
backup_path = os.path.join(self.helper.backup_path, server_id)
|
||||
if Helpers.is_os_windows():
|
||||
new_server_dir = Helpers.wtol_path(new_server_dir)
|
||||
backup_path = Helpers.wtol_path(backup_path)
|
||||
new_server_dir.replace(" ", "^ ")
|
||||
backup_path.replace(" ", "^ ")
|
||||
|
||||
helper.ensure_dir_exists(new_server_dir)
|
||||
helper.ensure_dir_exists(backup_path)
|
||||
server_path = helper.get_os_understandable_path(server_path)
|
||||
Helpers.ensure_dir_exists(new_server_dir)
|
||||
Helpers.ensure_dir_exists(backup_path)
|
||||
server_path = Helpers.get_os_understandable_path(server_path)
|
||||
try:
|
||||
file_helper.copy_dir(server_path, new_server_dir, True)
|
||||
FileHelpers.copy_dir(server_path, new_server_dir, True)
|
||||
except shutil.Error as ex:
|
||||
logger.error(f"Server import failed with error: {ex}")
|
||||
|
||||
@ -458,22 +468,22 @@ class Controller:
|
||||
)
|
||||
with open(
|
||||
os.path.join(new_server_dir, "server.properties"), "w", encoding="utf-8"
|
||||
) as f:
|
||||
f.write(f"server-port={port}")
|
||||
f.close()
|
||||
) as file:
|
||||
file.write(f"server-port={port}")
|
||||
file.close()
|
||||
|
||||
full_jar_path = os.path.join(new_server_dir, server_jar)
|
||||
|
||||
if helper.is_os_windows():
|
||||
if Helpers.is_os_windows():
|
||||
server_command = (
|
||||
f"java -Xms{helper.float_to_string(min_mem)}M "
|
||||
f"-Xmx{helper.float_to_string(max_mem)}M "
|
||||
f"java -Xms{Helpers.float_to_string(min_mem)}M "
|
||||
f"-Xmx{Helpers.float_to_string(max_mem)}M "
|
||||
f'-jar "{full_jar_path}" nogui'
|
||||
)
|
||||
else:
|
||||
server_command = (
|
||||
f"java -Xms{helper.float_to_string(min_mem)}M "
|
||||
f"-Xmx{helper.float_to_string(max_mem)}M "
|
||||
f"java -Xms{Helpers.float_to_string(min_mem)}M "
|
||||
f"-Xmx{Helpers.float_to_string(max_mem)}M "
|
||||
f"-jar {full_jar_path} nogui"
|
||||
)
|
||||
server_log_file = f"{new_server_dir}/logs/latest.log"
|
||||
@ -502,31 +512,31 @@ class Controller:
|
||||
max_mem: int,
|
||||
port: int,
|
||||
):
|
||||
server_id = helper.create_uuid()
|
||||
new_server_dir = os.path.join(helper.servers_dir, server_id)
|
||||
backup_path = os.path.join(helper.backup_path, server_id)
|
||||
if helper.is_os_windows():
|
||||
new_server_dir = helper.wtol_path(new_server_dir)
|
||||
backup_path = helper.wtol_path(backup_path)
|
||||
server_id = Helpers.create_uuid()
|
||||
new_server_dir = os.path.join(self.helper.servers_dir, server_id)
|
||||
backup_path = os.path.join(self.helper.backup_path, server_id)
|
||||
if Helpers.is_os_windows():
|
||||
new_server_dir = Helpers.wtol_path(new_server_dir)
|
||||
backup_path = Helpers.wtol_path(backup_path)
|
||||
new_server_dir.replace(" ", "^ ")
|
||||
backup_path.replace(" ", "^ ")
|
||||
|
||||
tempDir = helper.get_os_understandable_path(zip_path)
|
||||
helper.ensure_dir_exists(new_server_dir)
|
||||
helper.ensure_dir_exists(backup_path)
|
||||
temp_dir = Helpers.get_os_understandable_path(zip_path)
|
||||
Helpers.ensure_dir_exists(new_server_dir)
|
||||
Helpers.ensure_dir_exists(backup_path)
|
||||
has_properties = False
|
||||
# extracts archive to temp directory
|
||||
for item in os.listdir(tempDir):
|
||||
for item in os.listdir(temp_dir):
|
||||
if str(item) == "server.properties":
|
||||
has_properties = True
|
||||
try:
|
||||
if not os.path.isdir(os.path.join(tempDir, item)):
|
||||
file_helper.move_file(
|
||||
os.path.join(tempDir, item), os.path.join(new_server_dir, item)
|
||||
if not os.path.isdir(os.path.join(temp_dir, item)):
|
||||
FileHelpers.move_file(
|
||||
os.path.join(temp_dir, item), os.path.join(new_server_dir, item)
|
||||
)
|
||||
else:
|
||||
file_helper.move_dir(
|
||||
os.path.join(tempDir, item), os.path.join(new_server_dir, item)
|
||||
FileHelpers.move_dir(
|
||||
os.path.join(temp_dir, item), os.path.join(new_server_dir, item)
|
||||
)
|
||||
except Exception as ex:
|
||||
logger.error(f"ERROR IN ZIP IMPORT: {ex}")
|
||||
@ -537,22 +547,22 @@ class Controller:
|
||||
)
|
||||
with open(
|
||||
os.path.join(new_server_dir, "server.properties"), "w", encoding="utf-8"
|
||||
) as f:
|
||||
f.write(f"server-port={port}")
|
||||
f.close()
|
||||
) as file:
|
||||
file.write(f"server-port={port}")
|
||||
file.close()
|
||||
|
||||
full_jar_path = os.path.join(new_server_dir, server_jar)
|
||||
|
||||
if helper.is_os_windows():
|
||||
if Helpers.is_os_windows():
|
||||
server_command = (
|
||||
f"java -Xms{helper.float_to_string(min_mem)}M "
|
||||
f"-Xmx{helper.float_to_string(max_mem)}M "
|
||||
f"java -Xms{Helpers.float_to_string(min_mem)}M "
|
||||
f"-Xmx{Helpers.float_to_string(max_mem)}M "
|
||||
f'-jar "{full_jar_path}" nogui'
|
||||
)
|
||||
else:
|
||||
server_command = (
|
||||
f"java -Xms{helper.float_to_string(min_mem)}M "
|
||||
f"-Xmx{helper.float_to_string(max_mem)}M "
|
||||
f"java -Xms{Helpers.float_to_string(min_mem)}M "
|
||||
f"-Xmx{Helpers.float_to_string(max_mem)}M "
|
||||
f"-jar {full_jar_path} nogui"
|
||||
)
|
||||
logger.debug("command: " + server_command)
|
||||
@ -580,20 +590,20 @@ class Controller:
|
||||
def import_bedrock_server(
|
||||
self, server_name: str, server_path: str, server_exe: str, port: int
|
||||
):
|
||||
server_id = helper.create_uuid()
|
||||
new_server_dir = os.path.join(helper.servers_dir, server_id)
|
||||
backup_path = os.path.join(helper.backup_path, server_id)
|
||||
if helper.is_os_windows():
|
||||
new_server_dir = helper.wtol_path(new_server_dir)
|
||||
backup_path = helper.wtol_path(backup_path)
|
||||
server_id = Helpers.create_uuid()
|
||||
new_server_dir = os.path.join(self.helper.servers_dir, server_id)
|
||||
backup_path = os.path.join(self.helper.backup_path, server_id)
|
||||
if Helpers.is_os_windows():
|
||||
new_server_dir = Helpers.wtol_path(new_server_dir)
|
||||
backup_path = Helpers.wtol_path(backup_path)
|
||||
new_server_dir.replace(" ", "^ ")
|
||||
backup_path.replace(" ", "^ ")
|
||||
|
||||
helper.ensure_dir_exists(new_server_dir)
|
||||
helper.ensure_dir_exists(backup_path)
|
||||
server_path = helper.get_os_understandable_path(server_path)
|
||||
Helpers.ensure_dir_exists(new_server_dir)
|
||||
Helpers.ensure_dir_exists(backup_path)
|
||||
server_path = Helpers.get_os_understandable_path(server_path)
|
||||
try:
|
||||
file_helper.copy_dir(server_path, new_server_dir, True)
|
||||
FileHelpers.copy_dir(server_path, new_server_dir, True)
|
||||
except shutil.Error as ex:
|
||||
logger.error(f"Server import failed with error: {ex}")
|
||||
|
||||
@ -608,13 +618,13 @@ class Controller:
|
||||
)
|
||||
with open(
|
||||
os.path.join(new_server_dir, "server.properties"), "w", encoding="utf-8"
|
||||
) as f:
|
||||
f.write(f"server-port={port}")
|
||||
f.close()
|
||||
) as file:
|
||||
file.write(f"server-port={port}")
|
||||
file.close()
|
||||
|
||||
full_jar_path = os.path.join(new_server_dir, server_exe)
|
||||
|
||||
if helper.is_os_windows():
|
||||
if Helpers.is_os_windows():
|
||||
server_command = f'"{full_jar_path}"'
|
||||
else:
|
||||
server_command = f"./{server_exe}"
|
||||
@ -635,38 +645,38 @@ class Controller:
|
||||
server_type="minecraft-bedrock",
|
||||
)
|
||||
if os.name != "nt":
|
||||
if helper.check_file_exists(full_jar_path):
|
||||
if Helpers.check_file_exists(full_jar_path):
|
||||
os.chmod(full_jar_path, 0o2775)
|
||||
return new_id
|
||||
|
||||
def import_bedrock_zip_server(
|
||||
self, server_name: str, zip_path: str, server_exe: str, port: int
|
||||
):
|
||||
server_id = helper.create_uuid()
|
||||
new_server_dir = os.path.join(helper.servers_dir, server_id)
|
||||
backup_path = os.path.join(helper.backup_path, server_id)
|
||||
if helper.is_os_windows():
|
||||
new_server_dir = helper.wtol_path(new_server_dir)
|
||||
backup_path = helper.wtol_path(backup_path)
|
||||
server_id = Helpers.create_uuid()
|
||||
new_server_dir = os.path.join(self.helper.servers_dir, server_id)
|
||||
backup_path = os.path.join(self.helper.backup_path, server_id)
|
||||
if Helpers.is_os_windows():
|
||||
new_server_dir = Helpers.wtol_path(new_server_dir)
|
||||
backup_path = Helpers.wtol_path(backup_path)
|
||||
new_server_dir.replace(" ", "^ ")
|
||||
backup_path.replace(" ", "^ ")
|
||||
|
||||
tempDir = helper.get_os_understandable_path(zip_path)
|
||||
helper.ensure_dir_exists(new_server_dir)
|
||||
helper.ensure_dir_exists(backup_path)
|
||||
temp_dir = Helpers.get_os_understandable_path(zip_path)
|
||||
Helpers.ensure_dir_exists(new_server_dir)
|
||||
Helpers.ensure_dir_exists(backup_path)
|
||||
has_properties = False
|
||||
# extracts archive to temp directory
|
||||
for item in os.listdir(tempDir):
|
||||
for item in os.listdir(temp_dir):
|
||||
if str(item) == "server.properties":
|
||||
has_properties = True
|
||||
try:
|
||||
if not os.path.isdir(os.path.join(tempDir, item)):
|
||||
file_helper.move_file(
|
||||
os.path.join(tempDir, item), os.path.join(new_server_dir, item)
|
||||
if not os.path.isdir(os.path.join(temp_dir, item)):
|
||||
FileHelpers.move_file(
|
||||
os.path.join(temp_dir, item), os.path.join(new_server_dir, item)
|
||||
)
|
||||
else:
|
||||
file_helper.move_dir(
|
||||
os.path.join(tempDir, item), os.path.join(new_server_dir, item)
|
||||
FileHelpers.move_dir(
|
||||
os.path.join(temp_dir, item), os.path.join(new_server_dir, item)
|
||||
)
|
||||
except Exception as ex:
|
||||
logger.error(f"ERROR IN ZIP IMPORT: {ex}")
|
||||
@ -677,13 +687,13 @@ class Controller:
|
||||
)
|
||||
with open(
|
||||
os.path.join(new_server_dir, "server.properties"), "w", encoding="utf-8"
|
||||
) as f:
|
||||
f.write(f"server-port={port}")
|
||||
f.close()
|
||||
) as file:
|
||||
file.write(f"server-port={port}")
|
||||
file.close()
|
||||
|
||||
full_jar_path = os.path.join(new_server_dir, server_exe)
|
||||
|
||||
if helper.is_os_windows():
|
||||
if Helpers.is_os_windows():
|
||||
server_command = f'"{full_jar_path}"'
|
||||
else:
|
||||
server_command = f"./{server_exe}"
|
||||
@ -704,7 +714,7 @@ class Controller:
|
||||
server_type="minecraft-bedrock",
|
||||
)
|
||||
if os.name != "nt":
|
||||
if helper.check_file_exists(full_jar_path):
|
||||
if Helpers.check_file_exists(full_jar_path):
|
||||
os.chmod(full_jar_path, 0o2775)
|
||||
|
||||
return new_id
|
||||
@ -716,21 +726,24 @@ class Controller:
|
||||
def rename_backup_dir(self, old_server_id, new_server_id, new_uuid):
|
||||
server_data = self.servers.get_server_data_by_id(old_server_id)
|
||||
old_bu_path = server_data["backup_path"]
|
||||
Server_Perms_Controller.backup_role_swap(old_server_id, new_server_id)
|
||||
if not helper.is_os_windows():
|
||||
backup_path = helper.validate_traversal(helper.backup_path, old_bu_path)
|
||||
if helper.is_os_windows():
|
||||
backup_path = helper.validate_traversal(
|
||||
helper.wtol_path(helper.backup_path), helper.wtol_path(old_bu_path)
|
||||
ServerPermsController.backup_role_swap(old_server_id, new_server_id)
|
||||
if not Helpers.is_os_windows():
|
||||
backup_path = Helpers.validate_traversal(
|
||||
self.helper.backup_path, old_bu_path
|
||||
)
|
||||
backup_path = helper.wtol_path(str(backup_path))
|
||||
if Helpers.is_os_windows():
|
||||
backup_path = Helpers.validate_traversal(
|
||||
Helpers.wtol_path(self.helper.backup_path),
|
||||
Helpers.wtol_path(old_bu_path),
|
||||
)
|
||||
backup_path = Helpers.wtol_path(str(backup_path))
|
||||
backup_path.replace(" ", "^ ")
|
||||
backup_path = Path(backup_path)
|
||||
backup_path_components = list(backup_path.parts)
|
||||
backup_path_components[-1] = new_uuid
|
||||
new_bu_path = pathlib.PurePath(os.path.join(*backup_path_components))
|
||||
if os.path.isdir(new_bu_path):
|
||||
if helper.validate_traversal(helper.backup_path, new_bu_path):
|
||||
if Helpers.validate_traversal(self.helper.backup_path, new_bu_path):
|
||||
os.rmdir(new_bu_path)
|
||||
backup_path.rename(new_bu_path)
|
||||
|
||||
@ -748,7 +761,6 @@ class Controller:
|
||||
server_type: str,
|
||||
):
|
||||
# put data in the db
|
||||
|
||||
new_id = self.servers.create_server(
|
||||
name,
|
||||
server_uuid,
|
||||
@ -762,19 +774,21 @@ class Controller:
|
||||
server_port,
|
||||
)
|
||||
|
||||
if not helper.check_file_exists(os.path.join(server_dir, "crafty_managed.txt")):
|
||||
if not Helpers.check_file_exists(
|
||||
os.path.join(server_dir, "crafty_managed.txt")
|
||||
):
|
||||
try:
|
||||
# place a file in the dir saying it's owned by crafty
|
||||
with open(
|
||||
os.path.join(server_dir, "crafty_managed.txt"),
|
||||
"w",
|
||||
encoding="utf-8",
|
||||
) as f:
|
||||
f.write(
|
||||
) as file:
|
||||
file.write(
|
||||
"The server is managed by Crafty Controller.\n "
|
||||
"Leave this directory/files alone please"
|
||||
)
|
||||
f.close()
|
||||
file.close()
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Unable to create required server files due to :{e}")
|
||||
@ -787,25 +801,26 @@ class Controller:
|
||||
|
||||
def remove_server(self, server_id, files):
|
||||
counter = 0
|
||||
for s in self.servers_list:
|
||||
for server in self.servers_list:
|
||||
|
||||
# if this is the droid... im mean server we are looking for...
|
||||
if str(s["server_id"]) == str(server_id):
|
||||
if str(server["server_id"]) == str(server_id):
|
||||
server_data = self.get_server_data(server_id)
|
||||
server_name = server_data["server_name"]
|
||||
|
||||
logger.info(f"Deleting Server: ID {server_id} | Name: {server_name} ")
|
||||
console.info(f"Deleting Server: ID {server_id} | Name: {server_name} ")
|
||||
Console.info(f"Deleting Server: ID {server_id} | Name: {server_name} ")
|
||||
|
||||
srv_obj = s["server_obj"]
|
||||
srv_obj = server["server_obj"]
|
||||
srv_obj.server_scheduler.shutdown()
|
||||
running = srv_obj.check_running()
|
||||
|
||||
if running:
|
||||
self.stop_server(server_id)
|
||||
if files:
|
||||
try:
|
||||
file_helper.del_dirs(
|
||||
helper.get_os_understandable_path(
|
||||
FileHelpers.del_dirs(
|
||||
Helpers.get_os_understandable_path(
|
||||
self.servers.get_server_data_by_id(server_id)["path"]
|
||||
)
|
||||
)
|
||||
@ -814,11 +829,11 @@ class Controller:
|
||||
f"Unable to delete server files for server with ID: "
|
||||
f"{server_id} with error logged: {e}"
|
||||
)
|
||||
if helper.check_path_exists(
|
||||
if Helpers.check_path_exists(
|
||||
self.servers.get_server_data_by_id(server_id)["backup_path"]
|
||||
):
|
||||
file_helper.del_dirs(
|
||||
helper.get_os_understandable_path(
|
||||
FileHelpers.del_dirs(
|
||||
Helpers.get_os_understandable_path(
|
||||
self.servers.get_server_data_by_id(server_id)[
|
||||
"backup_path"
|
||||
]
|
||||
@ -827,7 +842,7 @@ class Controller:
|
||||
|
||||
# Cleanup scheduled tasks
|
||||
try:
|
||||
helpers_management.delete_scheduled_task_by_server(server_id)
|
||||
HelpersManagement.delete_scheduled_task_by_server(server_id)
|
||||
except DoesNotExist:
|
||||
logger.info("No scheduled jobs exist. Continuing.")
|
||||
# remove the server from the DB
|
||||
@ -840,8 +855,8 @@ class Controller:
|
||||
|
||||
@staticmethod
|
||||
def clear_unexecuted_commands():
|
||||
helpers_management.clear_unexecuted_commands()
|
||||
HelpersManagement.clear_unexecuted_commands()
|
||||
|
||||
@staticmethod
|
||||
def clear_support_status():
|
||||
helper_users.clear_support_status()
|
||||
HelperUsers.clear_support_status()
|
||||
|
@ -1,58 +1,43 @@
|
||||
import logging
|
||||
from playhouse.shortcuts import model_to_dict
|
||||
|
||||
from app.classes.models.users import Users, users_helper
|
||||
from app.classes.shared.helpers import helper
|
||||
from app.classes.shared.console import console
|
||||
|
||||
# To disable warning about unused import ; Users is imported from here in other places
|
||||
# pylint: disable=self-assigning-variable
|
||||
Users = Users
|
||||
|
||||
try:
|
||||
# pylint: disable=unused-import
|
||||
from peewee import SqliteDatabase, fn
|
||||
from playhouse.shortcuts import model_to_dict
|
||||
|
||||
except ModuleNotFoundError as err:
|
||||
helper.auto_installer_fix(err)
|
||||
from app.classes.shared.helpers import Helpers # pylint: disable=unused-import
|
||||
from app.classes.shared.console import Console
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
peewee_logger = logging.getLogger("peewee")
|
||||
peewee_logger.setLevel(logging.INFO)
|
||||
database = SqliteDatabase(
|
||||
helper.db_path, pragmas={"journal_mode": "wal", "cache_size": -1024 * 10}
|
||||
)
|
||||
|
||||
|
||||
class db_builder:
|
||||
@staticmethod
|
||||
def default_settings():
|
||||
class DatabaseBuilder:
|
||||
def __init__(self, database, helper, users_helper):
|
||||
self.database = database
|
||||
self.helper = helper
|
||||
self.users_helper = users_helper
|
||||
|
||||
def default_settings(self):
|
||||
logger.info("Fresh Install Detected - Creating Default Settings")
|
||||
console.info("Fresh Install Detected - Creating Default Settings")
|
||||
default_data = helper.find_default_password()
|
||||
Console.info("Fresh Install Detected - Creating Default Settings")
|
||||
default_data = self.helper.find_default_password()
|
||||
|
||||
username = default_data.get("username", "admin")
|
||||
password = default_data.get("password", "crafty")
|
||||
|
||||
users_helper.add_user(
|
||||
self.users_helper.add_user(
|
||||
username=username,
|
||||
password=password,
|
||||
email="default@example.com",
|
||||
superuser=True,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def is_fresh_install():
|
||||
def is_fresh_install(self):
|
||||
try:
|
||||
user = users_helper.get_by_id(1)
|
||||
user = self.users_helper.get_by_id(1)
|
||||
if user:
|
||||
return False
|
||||
except:
|
||||
return True
|
||||
|
||||
|
||||
class db_shortcuts:
|
||||
|
||||
class DatabaseShortcuts:
|
||||
# **********************************************************************************
|
||||
# Generic Databse Methods
|
||||
# **********************************************************************************
|
||||
@ -73,10 +58,3 @@ class db_shortcuts:
|
||||
def return_db_rows(model):
|
||||
data = [model_to_dict(row) for row in model]
|
||||
return data
|
||||
|
||||
|
||||
# **********************************************************************************
|
||||
# Static Accessors
|
||||
# **********************************************************************************
|
||||
installer = db_builder()
|
||||
db_helper = db_shortcuts()
|
||||
|
@ -1,481 +1,483 @@
|
||||
# pylint: skip-file
|
||||
from datetime import datetime
|
||||
import logging
|
||||
import typing as t
|
||||
import sys
|
||||
import os
|
||||
import re
|
||||
from functools import wraps
|
||||
from functools import cached_property
|
||||
|
||||
from app.classes.shared.helpers import helper
|
||||
from app.classes.shared.console import console
|
||||
|
||||
try:
|
||||
import peewee
|
||||
from playhouse.migrate import (
|
||||
SqliteMigrator,
|
||||
Operation,
|
||||
SQL,
|
||||
SqliteDatabase,
|
||||
make_index_name,
|
||||
)
|
||||
|
||||
except ModuleNotFoundError as e:
|
||||
helper.auto_installer_fix(e)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
MIGRATE_TABLE = "migratehistory"
|
||||
MIGRATE_TEMPLATE = '''# Generated by database migrator
|
||||
import peewee
|
||||
|
||||
def migrate(migrator, db):
|
||||
"""
|
||||
Write your migrations here.
|
||||
"""
|
||||
{migrate}
|
||||
|
||||
def rollback(migrator, db):
|
||||
"""
|
||||
Write your rollback migrations here.
|
||||
"""
|
||||
{rollback}'''
|
||||
|
||||
|
||||
class MigrateHistory(peewee.Model):
|
||||
"""
|
||||
Presents the migration history in a database.
|
||||
"""
|
||||
|
||||
name = peewee.CharField(unique=True)
|
||||
migrated_at = peewee.DateTimeField(default=datetime.utcnow)
|
||||
|
||||
# noinspection PyTypeChecker
|
||||
def __unicode__(self) -> str:
|
||||
"""
|
||||
String representation of this migration
|
||||
"""
|
||||
return self.name
|
||||
|
||||
class Meta:
|
||||
table_name = MIGRATE_TABLE
|
||||
|
||||
|
||||
def get_model(method):
|
||||
"""
|
||||
Convert string to model class.
|
||||
"""
|
||||
|
||||
@wraps(method)
|
||||
def wrapper(migrator, model, *args, **kwargs):
|
||||
if isinstance(model, str):
|
||||
return method(migrator, migrator.table_dict[model], *args, **kwargs)
|
||||
return method(migrator, model, *args, **kwargs)
|
||||
|
||||
return wrapper
|
||||
|
||||
|
||||
# noinspection PyProtectedMember
|
||||
class Migrator(object):
|
||||
def __init__(self, database: t.Union[peewee.Database, peewee.Proxy]):
|
||||
"""
|
||||
Initializes the migrator
|
||||
"""
|
||||
if isinstance(database, peewee.Proxy):
|
||||
database = database.obj
|
||||
self.database: SqliteDatabase = database
|
||||
self.table_dict: t.Dict[str, peewee.Model] = {}
|
||||
self.operations: t.List[t.Union[Operation, callable]] = []
|
||||
self.migrator = SqliteMigrator(database)
|
||||
|
||||
def run(self):
|
||||
"""
|
||||
Runs operations.
|
||||
"""
|
||||
for op in self.operations:
|
||||
if isinstance(op, Operation):
|
||||
op.run()
|
||||
else:
|
||||
op()
|
||||
self.clean()
|
||||
|
||||
def clean(self):
|
||||
"""
|
||||
Cleans the operations.
|
||||
"""
|
||||
self.operations = list()
|
||||
|
||||
def sql(self, sql: str, *params):
|
||||
"""
|
||||
Executes raw SQL.
|
||||
"""
|
||||
self.operations.append(SQL(sql, *params))
|
||||
|
||||
def create_table(self, model: peewee.Model) -> peewee.Model:
|
||||
"""
|
||||
Creates model and table in database.
|
||||
"""
|
||||
self.table_dict[model._meta.table_name] = model
|
||||
model._meta.database = self.database
|
||||
self.operations.append(model.create_table)
|
||||
return model
|
||||
|
||||
@get_model
|
||||
def drop_table(self, model: peewee.Model):
|
||||
"""
|
||||
Drops model and table from database.
|
||||
"""
|
||||
del self.table_dict[model._meta.table_name]
|
||||
self.operations.append(lambda: model.drop_table(cascade=False))
|
||||
|
||||
@get_model
|
||||
def add_columns(self, model: peewee.Model, **fields: peewee.Field) -> peewee.Model:
|
||||
"""
|
||||
Creates new fields.
|
||||
"""
|
||||
for name, field in fields.items():
|
||||
model._meta.add_field(name, field)
|
||||
self.operations.append(
|
||||
self.migrator.add_column(
|
||||
model._meta.table_name, field.column_name, field
|
||||
)
|
||||
)
|
||||
if field.unique:
|
||||
self.operations.append(
|
||||
self.migrator.add_index(
|
||||
model._meta.table_name, (field.column_name,), unique=True
|
||||
)
|
||||
)
|
||||
return model
|
||||
|
||||
@get_model
|
||||
def drop_columns(self, model: peewee.Model, names: str) -> peewee.Model:
|
||||
"""
|
||||
Removes fields from model.
|
||||
"""
|
||||
fields = [field for field in model._meta.fields.values() if field.name in names]
|
||||
for field in fields:
|
||||
self.__del_field__(model, field)
|
||||
if field.unique:
|
||||
# Drop unique index
|
||||
index_name = make_index_name(
|
||||
model._meta.table_name, [field.column_name]
|
||||
)
|
||||
self.operations.append(
|
||||
self.migrator.drop_index(model._meta.table_name, index_name)
|
||||
)
|
||||
self.operations.append(
|
||||
self.migrator.drop_column(
|
||||
model._meta.table_name, field.column_name, cascade=False
|
||||
)
|
||||
)
|
||||
return model
|
||||
|
||||
def __del_field__(self, model: peewee.Model, field: peewee.Field):
|
||||
"""
|
||||
Deletes field from model.
|
||||
"""
|
||||
model._meta.remove_field(field.name)
|
||||
delattr(model, field.name)
|
||||
if isinstance(field, peewee.ForeignKeyField):
|
||||
obj_id_name = field.column_name
|
||||
if field.column_name == field.name:
|
||||
obj_id_name += "_id"
|
||||
delattr(model, obj_id_name)
|
||||
delattr(field.rel_model, field.backref)
|
||||
|
||||
@get_model
|
||||
def rename_column(
|
||||
self, model: peewee.Model, old_name: str, new_name: str
|
||||
) -> peewee.Model:
|
||||
"""
|
||||
Renames field in model.
|
||||
"""
|
||||
field = model._meta.fields[old_name]
|
||||
if isinstance(field, peewee.ForeignKeyField):
|
||||
old_name = field.column_name
|
||||
self.__del_field__(model, field)
|
||||
field.name = field.column_name = new_name
|
||||
model._meta.add_field(new_name, field)
|
||||
if isinstance(field, peewee.ForeignKeyField):
|
||||
field.column_name = new_name = field.column_name + "_id"
|
||||
self.operations.append(
|
||||
self.migrator.rename_column(model._meta.table_name, old_name, new_name)
|
||||
)
|
||||
return model
|
||||
|
||||
@get_model
|
||||
def rename_table(self, model: peewee.Model, new_name: str) -> peewee.Model:
|
||||
"""
|
||||
Renames table in database.
|
||||
"""
|
||||
old_name = model._meta.table_name
|
||||
del self.table_dict[model._meta.table_name]
|
||||
model._meta.table_name = new_name
|
||||
self.table_dict[model._meta.table_name] = model
|
||||
self.operations.append(self.migrator.rename_table(old_name, new_name))
|
||||
return model
|
||||
|
||||
@get_model
|
||||
def add_index(
|
||||
self, model: peewee.Model, *columns: str, unique=False
|
||||
) -> peewee.Model:
|
||||
"""Create indexes."""
|
||||
model._meta.indexes.append((columns, unique))
|
||||
columns_ = []
|
||||
for col in columns:
|
||||
field = model._meta.fields.get(col)
|
||||
|
||||
if len(columns) == 1:
|
||||
field.unique = unique
|
||||
field.index = not unique
|
||||
|
||||
if isinstance(field, peewee.ForeignKeyField):
|
||||
col = col + "_id"
|
||||
|
||||
columns_.append(col)
|
||||
self.operations.append(
|
||||
self.migrator.add_index(model._meta.table_name, columns_, unique=unique)
|
||||
)
|
||||
return model
|
||||
|
||||
@get_model
|
||||
def drop_index(self, model: peewee.Model, *columns: str) -> peewee.Model:
|
||||
"""Drop indexes."""
|
||||
columns_ = []
|
||||
for col in columns:
|
||||
field = model._meta.fields.get(col)
|
||||
if not field:
|
||||
continue
|
||||
|
||||
if len(columns) == 1:
|
||||
field.unique = field.index = False
|
||||
|
||||
if isinstance(field, peewee.ForeignKeyField):
|
||||
col = col + "_id"
|
||||
columns_.append(col)
|
||||
index_name = make_index_name(model._meta.table_name, columns_)
|
||||
model._meta.indexes = [
|
||||
(cols, _) for (cols, _) in model._meta.indexes if columns != cols
|
||||
]
|
||||
self.operations.append(
|
||||
self.migrator.drop_index(model._meta.table_name, index_name)
|
||||
)
|
||||
return model
|
||||
|
||||
@get_model
|
||||
def add_not_null(self, model: peewee.Model, *names: str) -> peewee.Model:
|
||||
"""Add not null."""
|
||||
for name in names:
|
||||
field = model._meta.fields[name]
|
||||
field.null = False
|
||||
self.operations.append(
|
||||
self.migrator.add_not_null(model._meta.table_name, field.column_name)
|
||||
)
|
||||
return model
|
||||
|
||||
@get_model
|
||||
def drop_not_null(self, model: peewee.Model, *names: str) -> peewee.Model:
|
||||
"""Drop not null."""
|
||||
for name in names:
|
||||
field = model._meta.fields[name]
|
||||
field.null = True
|
||||
self.operations.append(
|
||||
self.migrator.drop_not_null(model._meta.table_name, field.column_name)
|
||||
)
|
||||
return model
|
||||
|
||||
@get_model
|
||||
def add_default(
|
||||
self, model: peewee.Model, name: str, default: t.Any
|
||||
) -> peewee.Model:
|
||||
"""Add default."""
|
||||
field = model._meta.fields[name]
|
||||
model._meta.defaults[field] = field.default = default
|
||||
self.operations.append(
|
||||
self.migrator.apply_default(model._meta.table_name, name, field)
|
||||
)
|
||||
return model
|
||||
|
||||
|
||||
# noinspection PyProtectedMember
|
||||
class MigrationManager(object):
|
||||
filemask = re.compile(r"[\d]+_[^\.]+\.py$")
|
||||
|
||||
def __init__(self, database: t.Union[peewee.Database, peewee.Proxy]):
|
||||
"""
|
||||
Initializes the migration manager.
|
||||
"""
|
||||
if not isinstance(database, (peewee.Database, peewee.Proxy)):
|
||||
raise RuntimeError("Invalid database: {}".format(database))
|
||||
self.database = database
|
||||
|
||||
@cached_property
|
||||
def model(self) -> t.Type[MigrateHistory]:
|
||||
"""
|
||||
Initialize and cache the MigrationHistory model.
|
||||
"""
|
||||
MigrateHistory._meta.database = self.database
|
||||
MigrateHistory._meta.table_name = "migratehistory"
|
||||
MigrateHistory._meta.schema = None
|
||||
MigrateHistory.create_table(True)
|
||||
return MigrateHistory
|
||||
|
||||
@property
|
||||
def done(self) -> t.List[str]:
|
||||
"""
|
||||
Scans migrations in the database.
|
||||
"""
|
||||
return [mm.name for mm in self.model.select().order_by(self.model.id)]
|
||||
|
||||
@property
|
||||
def todo(self):
|
||||
"""
|
||||
Scans migrations in the file system.
|
||||
"""
|
||||
if not os.path.exists(helper.migration_dir):
|
||||
logger.warning(
|
||||
"Migration directory: {} does not exist.".format(helper.migration_dir)
|
||||
)
|
||||
os.makedirs(helper.migration_dir)
|
||||
return sorted(
|
||||
f[:-3] for f in os.listdir(helper.migration_dir) if self.filemask.match(f)
|
||||
)
|
||||
|
||||
@property
|
||||
def diff(self) -> t.List[str]:
|
||||
"""
|
||||
Calculates difference between the filesystem and the database.
|
||||
"""
|
||||
done = set(self.done)
|
||||
return [name for name in self.todo if name not in done]
|
||||
|
||||
@cached_property
|
||||
def migrator(self) -> Migrator:
|
||||
"""
|
||||
Create migrator and setup it with fake migrations.
|
||||
"""
|
||||
migrator = Migrator(self.database)
|
||||
for name in self.done:
|
||||
self.up_one(name, migrator, True)
|
||||
return migrator
|
||||
|
||||
def compile(self, name, migrate="", rollback=""):
|
||||
"""
|
||||
Compiles a migration.
|
||||
"""
|
||||
name = datetime.utcnow().strftime("%Y%m%d%H%M%S") + "_" + name
|
||||
filename = name + ".py"
|
||||
path = os.path.join(helper.migration_dir, filename)
|
||||
with open(path, "w") as f:
|
||||
f.write(
|
||||
MIGRATE_TEMPLATE.format(
|
||||
migrate=migrate, rollback=rollback, name=filename
|
||||
)
|
||||
)
|
||||
|
||||
return name
|
||||
|
||||
def create(self, name: str = "auto", auto: bool = False) -> t.Optional[str]:
|
||||
"""
|
||||
Creates a migration.
|
||||
"""
|
||||
migrate = rollback = ""
|
||||
if auto:
|
||||
raise NotImplementedError
|
||||
|
||||
logger.info('Creating migration "{}"'.format(name))
|
||||
name = self.compile(name, migrate, rollback)
|
||||
logger.info('Migration has been created as "{}"'.format(name))
|
||||
return name
|
||||
|
||||
def clear(self):
|
||||
"""Clear migrations."""
|
||||
self.model.delete().execute()
|
||||
|
||||
def up(self, name: t.Optional[str] = None):
|
||||
"""
|
||||
Runs all unapplied migrations.
|
||||
"""
|
||||
logger.info("Starting migrations")
|
||||
console.info("Starting migrations")
|
||||
|
||||
done = []
|
||||
diff = self.diff
|
||||
if not diff:
|
||||
logger.info("There is nothing to migrate")
|
||||
console.info("There is nothing to migrate")
|
||||
return done
|
||||
|
||||
migrator = self.migrator
|
||||
for mname in diff:
|
||||
done.append(self.up_one(mname, self.migrator))
|
||||
if name and name == mname:
|
||||
break
|
||||
|
||||
return done
|
||||
|
||||
def read(self, name: str):
|
||||
"""
|
||||
Reads a migration from a file.
|
||||
"""
|
||||
call_params = dict()
|
||||
if helper.is_os_windows() and sys.version_info >= (3, 0):
|
||||
# if system is windows - force utf-8 encoding
|
||||
call_params["encoding"] = "utf-8"
|
||||
with open(os.path.join(helper.migration_dir, name + ".py"), **call_params) as f:
|
||||
code = f.read()
|
||||
scope = {}
|
||||
code = compile(code, "<string>", "exec", dont_inherit=True)
|
||||
exec(code, scope, None)
|
||||
return scope.get("migrate", lambda m, d: None), scope.get(
|
||||
"rollback", lambda m, d: None
|
||||
)
|
||||
|
||||
def up_one(
|
||||
self, name: str, migrator: Migrator, fake: bool = False, rollback: bool = False
|
||||
) -> str:
|
||||
"""
|
||||
Runs a migration with a given name.
|
||||
"""
|
||||
try:
|
||||
migrate_fn, rollback_fn = self.read(name)
|
||||
if fake:
|
||||
migrate_fn(migrator, self.database)
|
||||
migrator.clean()
|
||||
return name
|
||||
with self.database.transaction():
|
||||
if rollback:
|
||||
logger.info('Rolling back "{}"'.format(name))
|
||||
rollback_fn(migrator, self.database)
|
||||
migrator.run()
|
||||
self.model.delete().where(self.model.name == name).execute()
|
||||
else:
|
||||
logger.info('Migrate "{}"'.format(name))
|
||||
migrate_fn(migrator, self.database)
|
||||
migrator.run()
|
||||
if name not in self.done:
|
||||
self.model.create(name=name)
|
||||
|
||||
logger.info('Done "{}"'.format(name))
|
||||
return name
|
||||
|
||||
except Exception:
|
||||
self.database.rollback()
|
||||
operation_name = "Rollback" if rollback else "Migration"
|
||||
logger.exception("{} failed: {}".format(operation_name, name))
|
||||
raise
|
||||
|
||||
def down(self):
|
||||
"""
|
||||
Rolls back migrations.
|
||||
"""
|
||||
if not self.done:
|
||||
raise RuntimeError("No migrations are found.")
|
||||
|
||||
name = self.done[-1]
|
||||
|
||||
migrator = self.migrator
|
||||
self.up_one(name, migrator, False, True)
|
||||
logger.warning("Rolled back migration: {}".format(name))
|
||||
# pylint: skip-file
|
||||
from datetime import datetime
|
||||
import logging
|
||||
import typing as t
|
||||
import sys
|
||||
import os
|
||||
import re
|
||||
from functools import wraps
|
||||
from functools import cached_property
|
||||
import peewee
|
||||
from playhouse.migrate import (
|
||||
SqliteMigrator,
|
||||
Operation,
|
||||
SQL,
|
||||
SqliteDatabase,
|
||||
make_index_name,
|
||||
)
|
||||
|
||||
from app.classes.shared.console import Console
|
||||
from app.classes.shared.helpers import Helpers
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
MIGRATE_TABLE = "migratehistory"
|
||||
MIGRATE_TEMPLATE = '''# Generated by database migrator
|
||||
import peewee
|
||||
|
||||
def migrate(migrator, db):
|
||||
"""
|
||||
Write your migrations here.
|
||||
"""
|
||||
{migrate}
|
||||
|
||||
def rollback(migrator, db):
|
||||
"""
|
||||
Write your rollback migrations here.
|
||||
"""
|
||||
{rollback}'''
|
||||
|
||||
|
||||
class MigrateHistory(peewee.Model):
|
||||
"""
|
||||
Presents the migration history in a database.
|
||||
"""
|
||||
|
||||
name = peewee.CharField(unique=True)
|
||||
migrated_at = peewee.DateTimeField(default=datetime.utcnow)
|
||||
|
||||
# noinspection PyTypeChecker
|
||||
def __unicode__(self) -> str:
|
||||
"""
|
||||
String representation of this migration
|
||||
"""
|
||||
return self.name
|
||||
|
||||
class Meta:
|
||||
table_name = MIGRATE_TABLE
|
||||
|
||||
|
||||
def get_model(method):
|
||||
"""
|
||||
Convert string to model class.
|
||||
"""
|
||||
|
||||
@wraps(method)
|
||||
def wrapper(migrator, model, *args, **kwargs):
|
||||
if isinstance(model, str):
|
||||
return method(migrator, migrator.table_dict[model], *args, **kwargs)
|
||||
return method(migrator, model, *args, **kwargs)
|
||||
|
||||
return wrapper
|
||||
|
||||
|
||||
# noinspection PyProtectedMember
|
||||
class Migrator(object):
|
||||
def __init__(self, database: t.Union[peewee.Database, peewee.Proxy]):
|
||||
"""
|
||||
Initializes the migrator
|
||||
"""
|
||||
if isinstance(database, peewee.Proxy):
|
||||
database = database.obj
|
||||
self.database: SqliteDatabase = database
|
||||
self.table_dict: t.Dict[str, peewee.Model] = {}
|
||||
self.operations: t.List[t.Union[Operation, callable]] = []
|
||||
self.migrator = SqliteMigrator(database)
|
||||
|
||||
def run(self):
|
||||
"""
|
||||
Runs operations.
|
||||
"""
|
||||
for op in self.operations:
|
||||
if isinstance(op, Operation):
|
||||
op.run()
|
||||
else:
|
||||
op()
|
||||
self.clean()
|
||||
|
||||
def clean(self):
|
||||
"""
|
||||
Cleans the operations.
|
||||
"""
|
||||
self.operations = list()
|
||||
|
||||
def sql(self, sql: str, *params):
|
||||
"""
|
||||
Executes raw SQL.
|
||||
"""
|
||||
self.operations.append(SQL(sql, *params))
|
||||
|
||||
def create_table(self, model: peewee.Model) -> peewee.Model:
|
||||
"""
|
||||
Creates model and table in database.
|
||||
"""
|
||||
self.table_dict[model._meta.table_name] = model
|
||||
model._meta.database = self.database
|
||||
self.operations.append(model.create_table)
|
||||
return model
|
||||
|
||||
@get_model
|
||||
def drop_table(self, model: peewee.Model):
|
||||
"""
|
||||
Drops model and table from database.
|
||||
"""
|
||||
del self.table_dict[model._meta.table_name]
|
||||
self.operations.append(lambda: model.drop_table(cascade=False))
|
||||
|
||||
@get_model
|
||||
def add_columns(self, model: peewee.Model, **fields: peewee.Field) -> peewee.Model:
|
||||
"""
|
||||
Creates new fields.
|
||||
"""
|
||||
for name, field in fields.items():
|
||||
model._meta.add_field(name, field)
|
||||
self.operations.append(
|
||||
self.migrator.add_column(
|
||||
model._meta.table_name, field.column_name, field
|
||||
)
|
||||
)
|
||||
if field.unique:
|
||||
self.operations.append(
|
||||
self.migrator.add_index(
|
||||
model._meta.table_name, (field.column_name,), unique=True
|
||||
)
|
||||
)
|
||||
return model
|
||||
|
||||
@get_model
|
||||
def drop_columns(self, model: peewee.Model, names: str) -> peewee.Model:
|
||||
"""
|
||||
Removes fields from model.
|
||||
"""
|
||||
fields = [field for field in model._meta.fields.values() if field.name in names]
|
||||
for field in fields:
|
||||
self.__del_field__(model, field)
|
||||
if field.unique:
|
||||
# Drop unique index
|
||||
index_name = make_index_name(
|
||||
model._meta.table_name, [field.column_name]
|
||||
)
|
||||
self.operations.append(
|
||||
self.migrator.drop_index(model._meta.table_name, index_name)
|
||||
)
|
||||
self.operations.append(
|
||||
self.migrator.drop_column(
|
||||
model._meta.table_name, field.column_name, cascade=False
|
||||
)
|
||||
)
|
||||
return model
|
||||
|
||||
def __del_field__(self, model: peewee.Model, field: peewee.Field):
|
||||
"""
|
||||
Deletes field from model.
|
||||
"""
|
||||
model._meta.remove_field(field.name)
|
||||
delattr(model, field.name)
|
||||
if isinstance(field, peewee.ForeignKeyField):
|
||||
obj_id_name = field.column_name
|
||||
if field.column_name == field.name:
|
||||
obj_id_name += "_id"
|
||||
delattr(model, obj_id_name)
|
||||
delattr(field.rel_model, field.backref)
|
||||
|
||||
@get_model
|
||||
def rename_column(
|
||||
self, model: peewee.Model, old_name: str, new_name: str
|
||||
) -> peewee.Model:
|
||||
"""
|
||||
Renames field in model.
|
||||
"""
|
||||
field = model._meta.fields[old_name]
|
||||
if isinstance(field, peewee.ForeignKeyField):
|
||||
old_name = field.column_name
|
||||
self.__del_field__(model, field)
|
||||
field.name = field.column_name = new_name
|
||||
model._meta.add_field(new_name, field)
|
||||
if isinstance(field, peewee.ForeignKeyField):
|
||||
field.column_name = new_name = field.column_name + "_id"
|
||||
self.operations.append(
|
||||
self.migrator.rename_column(model._meta.table_name, old_name, new_name)
|
||||
)
|
||||
return model
|
||||
|
||||
@get_model
|
||||
def rename_table(self, model: peewee.Model, new_name: str) -> peewee.Model:
|
||||
"""
|
||||
Renames table in database.
|
||||
"""
|
||||
old_name = model._meta.table_name
|
||||
del self.table_dict[model._meta.table_name]
|
||||
model._meta.table_name = new_name
|
||||
self.table_dict[model._meta.table_name] = model
|
||||
self.operations.append(self.migrator.rename_table(old_name, new_name))
|
||||
return model
|
||||
|
||||
@get_model
|
||||
def add_index(
|
||||
self, model: peewee.Model, *columns: str, unique=False
|
||||
) -> peewee.Model:
|
||||
"""Create indexes."""
|
||||
model._meta.indexes.append((columns, unique))
|
||||
columns_ = []
|
||||
for col in columns:
|
||||
field = model._meta.fields.get(col)
|
||||
|
||||
if len(columns) == 1:
|
||||
field.unique = unique
|
||||
field.index = not unique
|
||||
|
||||
if isinstance(field, peewee.ForeignKeyField):
|
||||
col = col + "_id"
|
||||
|
||||
columns_.append(col)
|
||||
self.operations.append(
|
||||
self.migrator.add_index(model._meta.table_name, columns_, unique=unique)
|
||||
)
|
||||
return model
|
||||
|
||||
@get_model
|
||||
def drop_index(self, model: peewee.Model, *columns: str) -> peewee.Model:
|
||||
"""Drop indexes."""
|
||||
columns_ = []
|
||||
for col in columns:
|
||||
field = model._meta.fields.get(col)
|
||||
if not field:
|
||||
continue
|
||||
|
||||
if len(columns) == 1:
|
||||
field.unique = field.index = False
|
||||
|
||||
if isinstance(field, peewee.ForeignKeyField):
|
||||
col = col + "_id"
|
||||
columns_.append(col)
|
||||
index_name = make_index_name(model._meta.table_name, columns_)
|
||||
model._meta.indexes = [
|
||||
(cols, _) for (cols, _) in model._meta.indexes if columns != cols
|
||||
]
|
||||
self.operations.append(
|
||||
self.migrator.drop_index(model._meta.table_name, index_name)
|
||||
)
|
||||
return model
|
||||
|
||||
@get_model
|
||||
def add_not_null(self, model: peewee.Model, *names: str) -> peewee.Model:
|
||||
"""Add not null."""
|
||||
for name in names:
|
||||
field = model._meta.fields[name]
|
||||
field.null = False
|
||||
self.operations.append(
|
||||
self.migrator.add_not_null(model._meta.table_name, field.column_name)
|
||||
)
|
||||
return model
|
||||
|
||||
@get_model
|
||||
def drop_not_null(self, model: peewee.Model, *names: str) -> peewee.Model:
|
||||
"""Drop not null."""
|
||||
for name in names:
|
||||
field = model._meta.fields[name]
|
||||
field.null = True
|
||||
self.operations.append(
|
||||
self.migrator.drop_not_null(model._meta.table_name, field.column_name)
|
||||
)
|
||||
return model
|
||||
|
||||
@get_model
|
||||
def add_default(
|
||||
self, model: peewee.Model, name: str, default: t.Any
|
||||
) -> peewee.Model:
|
||||
"""Add default."""
|
||||
field = model._meta.fields[name]
|
||||
model._meta.defaults[field] = field.default = default
|
||||
self.operations.append(
|
||||
self.migrator.apply_default(model._meta.table_name, name, field)
|
||||
)
|
||||
return model
|
||||
|
||||
|
||||
# noinspection PyProtectedMember
|
||||
class MigrationManager(object):
|
||||
filemask = re.compile(r"[\d]+_[^\.]+\.py$")
|
||||
|
||||
def __init__(self, database: t.Union[peewee.Database, peewee.Proxy], helper):
|
||||
"""
|
||||
Initializes the migration manager.
|
||||
"""
|
||||
if not isinstance(database, (peewee.Database, peewee.Proxy)):
|
||||
raise RuntimeError("Invalid database: {}".format(database))
|
||||
self.database = database
|
||||
self.helper = helper
|
||||
|
||||
@cached_property
|
||||
def model(self) -> t.Type[MigrateHistory]:
|
||||
"""
|
||||
Initialize and cache the MigrationHistory model.
|
||||
"""
|
||||
MigrateHistory._meta.database = self.database
|
||||
MigrateHistory._meta.table_name = "migratehistory"
|
||||
MigrateHistory._meta.schema = None
|
||||
MigrateHistory.create_table(True)
|
||||
return MigrateHistory
|
||||
|
||||
@property
|
||||
def done(self) -> t.List[str]:
|
||||
"""
|
||||
Scans migrations in the database.
|
||||
"""
|
||||
return [mm.name for mm in self.model.select().order_by(self.model.id)]
|
||||
|
||||
@property
|
||||
def todo(self):
|
||||
"""
|
||||
Scans migrations in the file system.
|
||||
"""
|
||||
if not os.path.exists(self.helper.migration_dir):
|
||||
logger.warning(
|
||||
"Migration directory: {} does not exist.".format(
|
||||
self.helper.migration_dir
|
||||
)
|
||||
)
|
||||
os.makedirs(self.helper.migration_dir)
|
||||
return sorted(
|
||||
f[:-3]
|
||||
for f in os.listdir(self.helper.migration_dir)
|
||||
if self.filemask.match(f)
|
||||
)
|
||||
|
||||
@property
|
||||
def diff(self) -> t.List[str]:
|
||||
"""
|
||||
Calculates difference between the filesystem and the database.
|
||||
"""
|
||||
done = set(self.done)
|
||||
return [name for name in self.todo if name not in done]
|
||||
|
||||
@cached_property
|
||||
def migrator(self) -> Migrator:
|
||||
"""
|
||||
Create migrator and setup it with fake migrations.
|
||||
"""
|
||||
migrator = Migrator(self.database)
|
||||
for name in self.done:
|
||||
self.up_one(name, migrator, True)
|
||||
return migrator
|
||||
|
||||
def compile(self, name, migrate="", rollback=""):
|
||||
"""
|
||||
Compiles a migration.
|
||||
"""
|
||||
name = datetime.utcnow().strftime("%Y%m%d%H%M%S") + "_" + name
|
||||
filename = name + ".py"
|
||||
path = os.path.join(self.helper.migration_dir, filename)
|
||||
with open(path, "w") as f:
|
||||
f.write(
|
||||
MIGRATE_TEMPLATE.format(
|
||||
migrate=migrate, rollback=rollback, name=filename
|
||||
)
|
||||
)
|
||||
|
||||
return name
|
||||
|
||||
def create(self, name: str = "auto", auto: bool = False) -> t.Optional[str]:
|
||||
"""
|
||||
Creates a migration.
|
||||
"""
|
||||
migrate = rollback = ""
|
||||
if auto:
|
||||
raise NotImplementedError
|
||||
|
||||
logger.info('Creating migration "{}"'.format(name))
|
||||
name = self.compile(name, migrate, rollback)
|
||||
logger.info('Migration has been created as "{}"'.format(name))
|
||||
return name
|
||||
|
||||
def clear(self):
|
||||
"""Clear migrations."""
|
||||
self.model.delete().execute()
|
||||
|
||||
def up(self, name: t.Optional[str] = None):
|
||||
"""
|
||||
Runs all unapplied migrations.
|
||||
"""
|
||||
logger.info("Starting migrations")
|
||||
Console.info("Starting migrations")
|
||||
|
||||
done = []
|
||||
diff = self.diff
|
||||
if not diff:
|
||||
logger.info("There is nothing to migrate")
|
||||
Console.info("There is nothing to migrate")
|
||||
return done
|
||||
|
||||
migrator = self.migrator
|
||||
for mname in diff:
|
||||
done.append(self.up_one(mname, self.migrator))
|
||||
if name and name == mname:
|
||||
break
|
||||
|
||||
return done
|
||||
|
||||
def read(self, name: str):
|
||||
"""
|
||||
Reads a migration from a file.
|
||||
"""
|
||||
call_params = dict()
|
||||
if Helpers.is_os_windows() and sys.version_info >= (3, 0):
|
||||
# if system is windows - force utf-8 encoding
|
||||
call_params["encoding"] = "utf-8"
|
||||
with open(
|
||||
os.path.join(self.helper.migration_dir, name + ".py"), **call_params
|
||||
) as f:
|
||||
code = f.read()
|
||||
scope = {}
|
||||
code = compile(code, "<string>", "exec", dont_inherit=True)
|
||||
exec(code, scope, None)
|
||||
return scope.get("migrate", lambda m, d: None), scope.get(
|
||||
"rollback", lambda m, d: None
|
||||
)
|
||||
|
||||
def up_one(
|
||||
self, name: str, migrator: Migrator, fake: bool = False, rollback: bool = False
|
||||
) -> str:
|
||||
"""
|
||||
Runs a migration with a given name.
|
||||
"""
|
||||
try:
|
||||
migrate_fn, rollback_fn = self.read(name)
|
||||
if fake:
|
||||
migrate_fn(migrator, self.database)
|
||||
migrator.clean()
|
||||
return name
|
||||
with self.database.transaction():
|
||||
if rollback:
|
||||
logger.info('Rolling back "{}"'.format(name))
|
||||
rollback_fn(migrator, self.database)
|
||||
migrator.run()
|
||||
self.model.delete().where(self.model.name == name).execute()
|
||||
else:
|
||||
logger.info('Migrate "{}"'.format(name))
|
||||
migrate_fn(migrator, self.database)
|
||||
migrator.run()
|
||||
if name not in self.done:
|
||||
self.model.create(name=name)
|
||||
|
||||
logger.info('Done "{}"'.format(name))
|
||||
return name
|
||||
|
||||
except Exception:
|
||||
self.database.rollback()
|
||||
operation_name = "Rollback" if rollback else "Migration"
|
||||
logger.exception("{} failed: {}".format(operation_name, name))
|
||||
raise
|
||||
|
||||
def down(self):
|
||||
"""
|
||||
Rolls back migrations.
|
||||
"""
|
||||
if not self.done:
|
||||
raise RuntimeError("No migrations are found.")
|
||||
|
||||
name = self.done[-1]
|
||||
|
||||
migrator = self.migrator
|
||||
self.up_one(name, migrator, False, True)
|
||||
logger.warning("Rolled back migration: {}".format(name))
|
||||
|
@ -3,25 +3,25 @@ from enum import Enum
|
||||
|
||||
class PermissionHelper:
|
||||
@staticmethod
|
||||
def both_have_perm(a: str, b: str, permission_tested: Enum):
|
||||
return permission_helper.combine_perm_bool(
|
||||
a[permission_tested.value], b[permission_tested.value]
|
||||
def both_have_perm(
|
||||
permission_mask_a: str, permission_mask_b: str, permission_tested: Enum
|
||||
):
|
||||
return PermissionHelper.combine_perm_bool(
|
||||
permission_mask_a[permission_tested.value],
|
||||
permission_mask_b[permission_tested.value],
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def combine_perm(a: str, b: str) -> str:
|
||||
return "1" if (a == "1" and b == "1") else "0"
|
||||
def combine_perm(permission_mask_a: str, permission_mask_b: str) -> str:
|
||||
return "1" if (permission_mask_a == "1" and permission_mask_b == "1") else "0"
|
||||
|
||||
@staticmethod
|
||||
def combine_perm_bool(a: str, b: str) -> bool:
|
||||
return a == "1" and b == "1"
|
||||
def combine_perm_bool(permission_mask_a: str, permission_mask_b: str) -> bool:
|
||||
return permission_mask_a == "1" and permission_mask_b == "1"
|
||||
|
||||
@staticmethod
|
||||
def combine_masks(permission_mask_a: str, permission_mask_b: str) -> str:
|
||||
both_masks = zip(list(permission_mask_a), list(permission_mask_b))
|
||||
return "".join(
|
||||
map(lambda x: permission_helper.combine_perm(x[0], x[1]), both_masks)
|
||||
map(lambda x: PermissionHelper.combine_perm(x[0], x[1]), both_masks)
|
||||
)
|
||||
|
||||
|
||||
permission_helper = PermissionHelper()
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -4,24 +4,15 @@ import logging
|
||||
import threading
|
||||
import asyncio
|
||||
import datetime
|
||||
from tzlocal import get_localzone
|
||||
from apscheduler.events import EVENT_JOB_EXECUTED
|
||||
from apscheduler.schedulers.background import BackgroundScheduler
|
||||
from apscheduler.triggers.cron import CronTrigger
|
||||
|
||||
from app.classes.controllers.users_controller import Users_Controller
|
||||
from app.classes.minecraft.serverjars import server_jar_obj
|
||||
from app.classes.models.management import management_helper
|
||||
from app.classes.models.users import users_helper
|
||||
from app.classes.shared.helpers import helper
|
||||
from app.classes.shared.console import console
|
||||
from app.classes.models.management import HelpersManagement
|
||||
from app.classes.models.users import HelperUsers
|
||||
from app.classes.shared.console import Console
|
||||
from app.classes.web.tornado_handler import Webserver
|
||||
from app.classes.web.websocket_helper import websocket_helper
|
||||
|
||||
try:
|
||||
from tzlocal import get_localzone
|
||||
from apscheduler.events import EVENT_JOB_EXECUTED
|
||||
from apscheduler.schedulers.background import BackgroundScheduler
|
||||
from apscheduler.triggers.cron import CronTrigger
|
||||
|
||||
except ModuleNotFoundError as err:
|
||||
helper.auto_installer_fix(err)
|
||||
|
||||
logger = logging.getLogger("apscheduler")
|
||||
scheduler_intervals = {
|
||||
@ -41,14 +32,15 @@ scheduler_intervals = {
|
||||
|
||||
|
||||
class TasksManager:
|
||||
def __init__(self, controller):
|
||||
def __init__(self, helper, controller):
|
||||
self.helper = helper
|
||||
self.controller = controller
|
||||
self.tornado = Webserver(controller, self)
|
||||
self.tornado = Webserver(helper, controller, self)
|
||||
|
||||
self.tz = get_localzone()
|
||||
self.scheduler = BackgroundScheduler(timezone=str(self.tz))
|
||||
|
||||
self.users_controller = Users_Controller()
|
||||
self.users_controller = self.controller.users
|
||||
|
||||
self.webserver_thread = threading.Thread(
|
||||
target=self.tornado.run_tornado, daemon=True, name="tornado_thread"
|
||||
@ -78,7 +70,7 @@ class TasksManager:
|
||||
return self.main_thread_exiting
|
||||
|
||||
def reload_schedule_from_db(self):
|
||||
jobs = management_helper.get_schedules_enabled()
|
||||
jobs = HelpersManagement.get_schedules_enabled()
|
||||
logger.info("Reload from DB called. Current enabled schedules: ")
|
||||
for item in jobs:
|
||||
logger.info(f"JOB: {item}")
|
||||
@ -86,19 +78,19 @@ class TasksManager:
|
||||
def command_watcher(self):
|
||||
while True:
|
||||
# select any commands waiting to be processed
|
||||
commands = management_helper.get_unactioned_commands()
|
||||
for c in commands:
|
||||
commands = HelpersManagement.get_unactioned_commands()
|
||||
for cmd in commands:
|
||||
try:
|
||||
svr = self.controller.get_server_obj(c.server_id)
|
||||
svr = self.controller.get_server_obj(cmd.server_id)
|
||||
except:
|
||||
logger.error(
|
||||
"Server value requested does note exist! "
|
||||
"Purging item from waiting commands."
|
||||
)
|
||||
management_helper.mark_command_complete(c.command_id)
|
||||
HelpersManagement.mark_command_complete(cmd.command_id)
|
||||
|
||||
user_id = c.user_id
|
||||
command = c.command
|
||||
user_id = cmd.user_id
|
||||
command = cmd.command
|
||||
|
||||
if command == "start_server":
|
||||
svr.run_threaded_server(user_id)
|
||||
@ -116,19 +108,19 @@ class TasksManager:
|
||||
svr.jar_update()
|
||||
else:
|
||||
svr.send_command(command)
|
||||
management_helper.mark_command_complete(c.command_id)
|
||||
HelpersManagement.mark_command_complete(cmd.command_id)
|
||||
|
||||
time.sleep(1)
|
||||
|
||||
def _main_graceful_exit(self):
|
||||
try:
|
||||
os.remove(helper.session_file)
|
||||
os.remove(self.helper.session_file)
|
||||
self.controller.stop_all_servers()
|
||||
except:
|
||||
logger.info("Caught error during shutdown", exc_info=True)
|
||||
|
||||
logger.info("***** Crafty Shutting Down *****\n\n")
|
||||
console.info("***** Crafty Shutting Down *****\n\n")
|
||||
Console.info("***** Crafty Shutting Down *****\n\n")
|
||||
self.main_thread_exiting = True
|
||||
|
||||
def start_webserver(self):
|
||||
@ -136,7 +128,7 @@ class TasksManager:
|
||||
|
||||
def reload_webserver(self):
|
||||
self.tornado.stop_web_server()
|
||||
console.info("Waiting 3 seconds")
|
||||
Console.info("Waiting 3 seconds")
|
||||
time.sleep(3)
|
||||
self.webserver_thread = threading.Thread(
|
||||
target=self.tornado.run_tornado, daemon=True, name="tornado_thread"
|
||||
@ -148,20 +140,20 @@ class TasksManager:
|
||||
|
||||
def start_scheduler(self):
|
||||
logger.info("Launching Scheduler Thread...")
|
||||
console.info("Launching Scheduler Thread...")
|
||||
Console.info("Launching Scheduler Thread...")
|
||||
self.schedule_thread.start()
|
||||
logger.info("Launching command thread...")
|
||||
console.info("Launching command thread...")
|
||||
Console.info("Launching command thread...")
|
||||
self.command_thread.start()
|
||||
logger.info("Launching log watcher...")
|
||||
console.info("Launching log watcher...")
|
||||
Console.info("Launching log watcher...")
|
||||
self.log_watcher_thread.start()
|
||||
logger.info("Launching realtime thread...")
|
||||
console.info("Launching realtime thread...")
|
||||
Console.info("Launching realtime thread...")
|
||||
self.realtime_thread.start()
|
||||
|
||||
def scheduler_thread(self):
|
||||
schedules = management_helper.get_schedules_enabled()
|
||||
schedules = HelpersManagement.get_schedules_enabled()
|
||||
self.scheduler.add_listener(self.schedule_watcher, mask=EVENT_JOB_EXECUTED)
|
||||
# self.scheduler.add_job(
|
||||
# self.scheduler.print_jobs, "interval", seconds=10, id="-1"
|
||||
@ -173,7 +165,7 @@ class TasksManager:
|
||||
if schedule.cron_string != "":
|
||||
try:
|
||||
self.scheduler.add_job(
|
||||
management_helper.add_command,
|
||||
HelpersManagement.add_command,
|
||||
CronTrigger.from_crontab(
|
||||
schedule.cron_string, timezone=str(self.tz)
|
||||
),
|
||||
@ -186,16 +178,18 @@ class TasksManager:
|
||||
],
|
||||
)
|
||||
except Exception as e:
|
||||
console.error(f"Failed to schedule task with error: {e}.")
|
||||
console.warning("Removing failed task from DB.")
|
||||
Console.error(f"Failed to schedule task with error: {e}.")
|
||||
Console.warning("Removing failed task from DB.")
|
||||
logger.error(f"Failed to schedule task with error: {e}.")
|
||||
logger.warning("Removing failed task from DB.")
|
||||
# remove items from DB if task fails to add to apscheduler
|
||||
management_helper.delete_scheduled_task(schedule.schedule_id)
|
||||
self.controller.management_helper.delete_scheduled_task(
|
||||
schedule.schedule_id
|
||||
)
|
||||
else:
|
||||
if schedule.interval_type == "hours":
|
||||
self.scheduler.add_job(
|
||||
management_helper.add_command,
|
||||
HelpersManagement.add_command,
|
||||
"cron",
|
||||
minute=0,
|
||||
hour="*/" + str(schedule.interval),
|
||||
@ -209,7 +203,7 @@ class TasksManager:
|
||||
)
|
||||
elif schedule.interval_type == "minutes":
|
||||
self.scheduler.add_job(
|
||||
management_helper.add_command,
|
||||
HelpersManagement.add_command,
|
||||
"cron",
|
||||
minute="*/" + str(schedule.interval),
|
||||
id=str(schedule.schedule_id),
|
||||
@ -223,7 +217,7 @@ class TasksManager:
|
||||
elif schedule.interval_type == "days":
|
||||
curr_time = schedule.start_time.split(":")
|
||||
self.scheduler.add_job(
|
||||
management_helper.add_command,
|
||||
HelpersManagement.add_command,
|
||||
"cron",
|
||||
day="*/" + str(schedule.interval),
|
||||
hour=curr_time[0],
|
||||
@ -243,7 +237,7 @@ class TasksManager:
|
||||
logger.info(f"JOB: {item}")
|
||||
|
||||
def schedule_job(self, job_data):
|
||||
sch_id = management_helper.create_scheduled_task(
|
||||
sch_id = HelpersManagement.create_scheduled_task(
|
||||
job_data["server_id"],
|
||||
job_data["action"],
|
||||
job_data["interval"],
|
||||
@ -260,13 +254,13 @@ class TasksManager:
|
||||
# Checks to make sure some doofus didn't actually make the newly
|
||||
# created task a child of itself.
|
||||
if str(job_data["parent"]) == str(sch_id):
|
||||
management_helper.update_scheduled_task(sch_id, {"parent": None})
|
||||
HelpersManagement.update_scheduled_task(sch_id, {"parent": None})
|
||||
# Check to see if it's enabled and is not a chain reaction.
|
||||
if job_data["enabled"] and job_data["interval_type"] != "reaction":
|
||||
if job_data["cron_string"] != "":
|
||||
try:
|
||||
self.scheduler.add_job(
|
||||
management_helper.add_command,
|
||||
HelpersManagement.add_command,
|
||||
CronTrigger.from_crontab(
|
||||
job_data["cron_string"], timezone=str(self.tz)
|
||||
),
|
||||
@ -279,16 +273,16 @@ class TasksManager:
|
||||
],
|
||||
)
|
||||
except Exception as e:
|
||||
console.error(f"Failed to schedule task with error: {e}.")
|
||||
console.warning("Removing failed task from DB.")
|
||||
Console.error(f"Failed to schedule task with error: {e}.")
|
||||
Console.warning("Removing failed task from DB.")
|
||||
logger.error(f"Failed to schedule task with error: {e}.")
|
||||
logger.warning("Removing failed task from DB.")
|
||||
# remove items from DB if task fails to add to apscheduler
|
||||
management_helper.delete_scheduled_task(sch_id)
|
||||
self.controller.management_helper.delete_scheduled_task(sch_id)
|
||||
else:
|
||||
if job_data["interval_type"] == "hours":
|
||||
self.scheduler.add_job(
|
||||
management_helper.add_command,
|
||||
HelpersManagement.add_command,
|
||||
"cron",
|
||||
minute=0,
|
||||
hour="*/" + str(job_data["interval"]),
|
||||
@ -302,7 +296,7 @@ class TasksManager:
|
||||
)
|
||||
elif job_data["interval_type"] == "minutes":
|
||||
self.scheduler.add_job(
|
||||
management_helper.add_command,
|
||||
HelpersManagement.add_command,
|
||||
"cron",
|
||||
minute="*/" + str(job_data["interval"]),
|
||||
id=str(sch_id),
|
||||
@ -316,7 +310,7 @@ class TasksManager:
|
||||
elif job_data["interval_type"] == "days":
|
||||
curr_time = job_data["start_time"].split(":")
|
||||
self.scheduler.add_job(
|
||||
management_helper.add_command,
|
||||
HelpersManagement.add_command,
|
||||
"cron",
|
||||
day="*/" + str(job_data["interval"]),
|
||||
hour=curr_time[0],
|
||||
@ -335,18 +329,18 @@ class TasksManager:
|
||||
logger.info(f"JOB: {item}")
|
||||
|
||||
def remove_all_server_tasks(self, server_id):
|
||||
schedules = management_helper.get_schedules_by_server(server_id)
|
||||
schedules = HelpersManagement.get_schedules_by_server(server_id)
|
||||
for schedule in schedules:
|
||||
if schedule.interval != "reaction":
|
||||
self.remove_job(schedule.schedule_id)
|
||||
|
||||
def remove_job(self, sch_id):
|
||||
job = management_helper.get_scheduled_task_model(sch_id)
|
||||
for schedule in management_helper.get_child_schedules(sch_id):
|
||||
management_helper.update_scheduled_task(
|
||||
job = HelpersManagement.get_scheduled_task_model(sch_id)
|
||||
for schedule in HelpersManagement.get_child_schedules(sch_id):
|
||||
self.controller.management_helper.update_scheduled_task(
|
||||
schedule.schedule_id, {"parent": None}
|
||||
)
|
||||
management_helper.delete_scheduled_task(sch_id)
|
||||
self.controller.management_helper.delete_scheduled_task(sch_id)
|
||||
if job.enabled and job.interval_type != "reaction":
|
||||
self.scheduler.remove_job(str(sch_id))
|
||||
logger.info(f"Job with ID {sch_id} was deleted.")
|
||||
@ -358,11 +352,11 @@ class TasksManager:
|
||||
)
|
||||
|
||||
def update_job(self, sch_id, job_data):
|
||||
management_helper.update_scheduled_task(sch_id, job_data)
|
||||
HelpersManagement.update_scheduled_task(sch_id, job_data)
|
||||
# Checks to make sure some doofus didn't actually make the newly
|
||||
# created task a child of itself.
|
||||
if str(job_data["parent"]) == str(sch_id):
|
||||
management_helper.update_scheduled_task(sch_id, {"parent": None})
|
||||
HelpersManagement.update_scheduled_task(sch_id, {"parent": None})
|
||||
try:
|
||||
if job_data["interval"] != "reaction":
|
||||
self.scheduler.remove_job(str(sch_id))
|
||||
@ -377,7 +371,7 @@ class TasksManager:
|
||||
if job_data["cron_string"] != "":
|
||||
try:
|
||||
self.scheduler.add_job(
|
||||
management_helper.add_command,
|
||||
HelpersManagement.add_command,
|
||||
CronTrigger.from_crontab(
|
||||
job_data["cron_string"], timezone=str(self.tz)
|
||||
),
|
||||
@ -390,13 +384,13 @@ class TasksManager:
|
||||
],
|
||||
)
|
||||
except Exception as e:
|
||||
console.error(f"Failed to schedule task with error: {e}.")
|
||||
console.info("Removing failed task from DB.")
|
||||
management_helper.delete_scheduled_task(sch_id)
|
||||
Console.error(f"Failed to schedule task with error: {e}.")
|
||||
Console.info("Removing failed task from DB.")
|
||||
self.controller.management_helper.delete_scheduled_task(sch_id)
|
||||
else:
|
||||
if job_data["interval_type"] == "hours":
|
||||
self.scheduler.add_job(
|
||||
management_helper.add_command,
|
||||
HelpersManagement.add_command,
|
||||
"cron",
|
||||
minute=0,
|
||||
hour="*/" + str(job_data["interval"]),
|
||||
@ -410,7 +404,7 @@ class TasksManager:
|
||||
)
|
||||
elif job_data["interval_type"] == "minutes":
|
||||
self.scheduler.add_job(
|
||||
management_helper.add_command,
|
||||
HelpersManagement.add_command,
|
||||
"cron",
|
||||
minute="*/" + str(job_data["interval"]),
|
||||
id=str(sch_id),
|
||||
@ -424,7 +418,7 @@ class TasksManager:
|
||||
elif job_data["interval_type"] == "days":
|
||||
curr_time = job_data["start_time"].split(":")
|
||||
self.scheduler.add_job(
|
||||
management_helper.add_command,
|
||||
HelpersManagement.add_command,
|
||||
"cron",
|
||||
day="*/" + str(job_data["interval"]),
|
||||
hour=curr_time[0],
|
||||
@ -450,10 +444,12 @@ class TasksManager:
|
||||
def schedule_watcher(self, event):
|
||||
if not event.exception:
|
||||
if str(event.job_id).isnumeric():
|
||||
task = management_helper.get_scheduled_task_model(int(event.job_id))
|
||||
management_helper.add_to_audit_log_raw(
|
||||
task = self.controller.management.get_scheduled_task_model(
|
||||
int(event.job_id)
|
||||
)
|
||||
self.controller.management.add_to_audit_log_raw(
|
||||
"system",
|
||||
users_helper.get_user_id_by_name("system"),
|
||||
HelperUsers.get_user_id_by_name("system"),
|
||||
task.server_id,
|
||||
f"Task with id {task.schedule_id} completed successfully",
|
||||
"127.0.0.1",
|
||||
@ -465,7 +461,7 @@ class TasksManager:
|
||||
# check for any child tasks for this. It's kind of backward,
|
||||
# but this makes DB management a lot easier. One to one
|
||||
# instead of one to many.
|
||||
for schedule in management_helper.get_child_schedules_by_server(
|
||||
for schedule in HelpersManagement.get_child_schedules_by_server(
|
||||
task.schedule_id, task.server_id
|
||||
):
|
||||
# event job ID's are strings so we need to look at
|
||||
@ -476,7 +472,7 @@ class TasksManager:
|
||||
seconds=schedule.delay
|
||||
)
|
||||
self.scheduler.add_job(
|
||||
management_helper.add_command,
|
||||
HelpersManagement.add_command,
|
||||
"date",
|
||||
run_date=delaytime,
|
||||
id=str(schedule.schedule_id),
|
||||
@ -496,11 +492,11 @@ class TasksManager:
|
||||
logger.error(f"Task failed with error: {event.exception}")
|
||||
|
||||
def start_stats_recording(self):
|
||||
stats_update_frequency = helper.get_setting("stats_update_frequency")
|
||||
stats_update_frequency = self.helper.get_setting("stats_update_frequency")
|
||||
logger.info(
|
||||
f"Stats collection frequency set to {stats_update_frequency} seconds"
|
||||
)
|
||||
console.info(
|
||||
Console.info(
|
||||
f"Stats collection frequency set to {stats_update_frequency} seconds"
|
||||
)
|
||||
|
||||
@ -516,36 +512,39 @@ class TasksManager:
|
||||
|
||||
def serverjar_cache_refresher(self):
|
||||
logger.info("Refreshing serverjars.com cache on start")
|
||||
server_jar_obj.refresh_cache()
|
||||
self.controller.server_jars.refresh_cache()
|
||||
|
||||
logger.info("Scheduling Serverjars.com cache refresh service every 12 hours")
|
||||
self.scheduler.add_job(
|
||||
server_jar_obj.refresh_cache, "interval", hours=12, id="serverjars"
|
||||
self.controller.server_jars.refresh_cache,
|
||||
"interval",
|
||||
hours=12,
|
||||
id="serverjars",
|
||||
)
|
||||
|
||||
def realtime(self):
|
||||
loop = asyncio.new_event_loop()
|
||||
asyncio.set_event_loop(loop)
|
||||
|
||||
host_stats = management_helper.get_latest_hosts_stats()
|
||||
host_stats = HelpersManagement.get_latest_hosts_stats()
|
||||
|
||||
while True:
|
||||
|
||||
if host_stats.get(
|
||||
"cpu_usage"
|
||||
) != management_helper.get_latest_hosts_stats().get(
|
||||
) != HelpersManagement.get_latest_hosts_stats().get(
|
||||
"cpu_usage"
|
||||
) or host_stats.get(
|
||||
"mem_percent"
|
||||
) != management_helper.get_latest_hosts_stats().get(
|
||||
) != HelpersManagement.get_latest_hosts_stats().get(
|
||||
"mem_percent"
|
||||
):
|
||||
# Stats are different
|
||||
|
||||
host_stats = management_helper.get_latest_hosts_stats()
|
||||
if len(websocket_helper.clients) > 0:
|
||||
host_stats = HelpersManagement.get_latest_hosts_stats()
|
||||
if len(self.helper.websocket_helper.clients) > 0:
|
||||
# There are clients
|
||||
websocket_helper.broadcast_page(
|
||||
self.helper.websocket_helper.broadcast_page(
|
||||
"/panel/dashboard",
|
||||
"update_host_stats",
|
||||
{
|
||||
@ -557,6 +556,7 @@ class TasksManager:
|
||||
"mem_usage": host_stats.get("mem_usage"),
|
||||
},
|
||||
)
|
||||
time.sleep(1)
|
||||
|
||||
def log_watcher(self):
|
||||
self.controller.servers.check_for_old_logs()
|
||||
|
@ -3,15 +3,17 @@ import logging
|
||||
import os
|
||||
import typing as t
|
||||
|
||||
from app.classes.shared.console import console
|
||||
from app.classes.shared.helpers import helper
|
||||
from app.classes.shared.console import Console
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Translation:
|
||||
def __init__(self):
|
||||
self.translations_path = os.path.join(helper.root_dir, "app", "translations")
|
||||
def __init__(self, helper):
|
||||
self.helper = helper
|
||||
self.translations_path = os.path.join(
|
||||
self.helper.root_dir, "app", "translations"
|
||||
)
|
||||
self.cached_translation = None
|
||||
self.cached_translation_lang = None
|
||||
|
||||
@ -59,7 +61,7 @@ class Translation:
|
||||
f"Translation File Error: page {page} "
|
||||
f"does not exist for lang {language}"
|
||||
)
|
||||
console.error(
|
||||
Console.error(
|
||||
f"Translation File Error: page {page} "
|
||||
f"does not exist for lang {language}"
|
||||
)
|
||||
@ -73,7 +75,7 @@ class Translation:
|
||||
f"Translation File Error: word {word} does not exist on page "
|
||||
f"{page} for lang {language}"
|
||||
)
|
||||
console.error(
|
||||
Console.error(
|
||||
f"Translation File Error: word {word} does not exist on page "
|
||||
f"{page} for lang {language}"
|
||||
)
|
||||
@ -83,10 +85,7 @@ class Translation:
|
||||
logger.critical(
|
||||
f"Translation File Error: Unable to read {language_file} due to {e}"
|
||||
)
|
||||
console.critical(
|
||||
Console.critical(
|
||||
f"Translation File Error: Unable to read {language_file} due to {e}"
|
||||
)
|
||||
return None
|
||||
|
||||
|
||||
translation = Translation()
|
||||
|
@ -3,23 +3,16 @@ import html
|
||||
import re
|
||||
import logging
|
||||
import time
|
||||
import bleach
|
||||
import tornado.web
|
||||
import tornado.escape
|
||||
|
||||
from app.classes.models.server_permissions import Enum_Permissions_Server
|
||||
from app.classes.shared.console import console
|
||||
from app.classes.shared.helpers import helper
|
||||
from app.classes.shared.translation import translation
|
||||
from app.classes.models.server_permissions import EnumPermissionsServer
|
||||
from app.classes.shared.console import Console
|
||||
from app.classes.shared.helpers import Helpers
|
||||
from app.classes.shared.server import ServerOutBuf
|
||||
from app.classes.web.websocket_helper import websocket_helper
|
||||
from app.classes.web.base_handler import BaseHandler
|
||||
|
||||
try:
|
||||
import bleach
|
||||
import tornado.web
|
||||
import tornado.escape
|
||||
|
||||
except ModuleNotFoundError as ex:
|
||||
helper.auto_installer_fix(ex)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@ -67,19 +60,19 @@ class AjaxHandler(BaseHandler):
|
||||
)
|
||||
|
||||
if full_log:
|
||||
log_lines = helper.get_setting("max_log_lines")
|
||||
data = helper.tail_file(
|
||||
helper.get_os_understandable_path(server_data["log_path"]),
|
||||
log_lines = self.helper.get_setting("max_log_lines")
|
||||
data = Helpers.tail_file(
|
||||
Helpers.get_os_understandable_path(server_data["log_path"]),
|
||||
log_lines,
|
||||
)
|
||||
else:
|
||||
data = ServerOutBuf.lines.get(server_id, [])
|
||||
|
||||
for d in data:
|
||||
for line in data:
|
||||
try:
|
||||
d = re.sub("(\033\\[(0;)?[0-9]*[A-z]?(;[0-9])?m?)|(> )", "", d)
|
||||
d = re.sub("[A-z]{2}\b\b", "", d)
|
||||
line = helper.log_colors(html.escape(d))
|
||||
line = re.sub("(\033\\[(0;)?[0-9]*[A-z]?(;[0-9])?m?)", "", line)
|
||||
line = re.sub("[A-z]{2}\b\b", "", line)
|
||||
line = self.helper.log_colors(html.escape(line))
|
||||
self.write(f"{line}<br />")
|
||||
# self.write(d.encode("utf-8"))
|
||||
|
||||
@ -87,7 +80,7 @@ class AjaxHandler(BaseHandler):
|
||||
logger.warning(f"Skipping Log Line due to error: {e}")
|
||||
|
||||
elif page == "announcements":
|
||||
data = helper.get_announcements()
|
||||
data = Helpers.get_announcements()
|
||||
page_data["notify_data"] = data
|
||||
self.render_page("ajax/notify.html", page_data)
|
||||
|
||||
@ -95,9 +88,9 @@ class AjaxHandler(BaseHandler):
|
||||
path = self.get_argument("path", None)
|
||||
|
||||
self.write(
|
||||
helper.get_os_understandable_path(path)
|
||||
Helpers.get_os_understandable_path(path)
|
||||
+ "\n"
|
||||
+ helper.generate_zip_tree(path)
|
||||
+ Helpers.generate_zip_tree(path)
|
||||
)
|
||||
self.finish()
|
||||
|
||||
@ -105,9 +98,9 @@ class AjaxHandler(BaseHandler):
|
||||
path = self.get_argument("path", None)
|
||||
|
||||
self.write(
|
||||
helper.get_os_understandable_path(path)
|
||||
Helpers.get_os_understandable_path(path)
|
||||
+ "\n"
|
||||
+ helper.generate_zip_dir(path)
|
||||
+ Helpers.generate_zip_dir(path)
|
||||
)
|
||||
self.finish()
|
||||
|
||||
@ -141,15 +134,15 @@ class AjaxHandler(BaseHandler):
|
||||
\n<div id="{dpath}" data-path="{dpath}" data-name="{filename}" class="tree-caret tree-ctx-item tree-folder">
|
||||
<input type="checkbox" class="checkBoxClass" name="root_path" value="{dpath}" checked>
|
||||
<span id="{dpath}span" class="files-tree-title" data-path="{dpath}" data-name="{filename}" onclick="getDirView(event)">
|
||||
<i class="far fa-folder"></i>
|
||||
<i class="far fa-folder-open"></i>
|
||||
<i style="color: #8862e0;" class="far fa-folder"></i>
|
||||
<i style="color: #8862e0;" class="far fa-folder-open"></i>
|
||||
<strong>{filename}</strong>
|
||||
</span>
|
||||
</input></div><li>
|
||||
\n"""
|
||||
else:
|
||||
output += f"""<li
|
||||
class="tree-nested d-block tree-ctx-item tree-file"
|
||||
class="d-block tree-ctx-item tree-file"
|
||||
data-path="{dpath}"
|
||||
data-name="{filename}"
|
||||
onclick=""><input type='checkbox' class="checkBoxClass" name='root_path' value="{dpath}" checked><span style="margin-right: 6px;">
|
||||
@ -161,21 +154,21 @@ class AjaxHandler(BaseHandler):
|
||||
\n<div id="{dpath}" data-path="{dpath}" data-name="{filename}" class="tree-caret tree-ctx-item tree-folder">
|
||||
<input type="checkbox" class="checkBoxClass" name="root_path" value="{dpath}">
|
||||
<span id="{dpath}span" class="files-tree-title" data-path="{dpath}" data-name="{filename}" onclick="getDirView(event)">
|
||||
<i class="far fa-folder"></i>
|
||||
<i class="far fa-folder-open"></i>
|
||||
<i style="color: #8862e0;" class="far fa-folder"></i>
|
||||
<i style="color: #8862e0;" class="far fa-folder-open"></i>
|
||||
<strong>{filename}</strong>
|
||||
</span>
|
||||
</input></div><li>
|
||||
\n"""
|
||||
else:
|
||||
output += f"""<li
|
||||
class="tree-nested d-block tree-ctx-item tree-file"
|
||||
class="d-block tree-ctx-item tree-file"
|
||||
data-path="{dpath}"
|
||||
data-name="{filename}"
|
||||
onclick=""><input type='checkbox' class="checkBoxClass" name='root_path' value="{dpath}">
|
||||
<span style="margin-right: 6px;"><i class="far fa-file">
|
||||
</i></span></input>{filename}</li>"""
|
||||
self.write(helper.get_os_understandable_path(folder) + "\n" + output)
|
||||
self.write(Helpers.get_os_understandable_path(folder) + "\n" + output)
|
||||
self.finish()
|
||||
|
||||
elif page == "get_backup_dir":
|
||||
@ -205,7 +198,7 @@ class AjaxHandler(BaseHandler):
|
||||
if os.path.isdir(rel):
|
||||
output += f"""<li class="tree-item" data-path="{dpath}">
|
||||
\n<div id="{dpath}" data-path="{dpath}" data-name="{filename}" class="tree-caret tree-ctx-item tree-folder">
|
||||
<input type="checkbox" name="root_path" value="{dpath}">
|
||||
<input type="checkbox" name="root_path" value="{dpath}" checked>
|
||||
<span id="{dpath}span" class="files-tree-title" data-path="{dpath}" data-name="{filename}" onclick="getDirView(event)">
|
||||
<i class="far fa-folder"></i>
|
||||
<i class="far fa-folder-open"></i>
|
||||
@ -217,7 +210,7 @@ class AjaxHandler(BaseHandler):
|
||||
class="tree-item tree-nested d-block tree-ctx-item tree-file"
|
||||
data-path="{dpath}"
|
||||
data-name="{filename}"
|
||||
onclick=""><input type='checkbox' name='root_path' value='{dpath}'><span style="margin-right: 6px;">
|
||||
onclick=""><input type='checkbox' name='root_path' value='{dpath}' checked><span style="margin-right: 6px;">
|
||||
<i class="far fa-file"></i></span></input>{filename}</li>"""
|
||||
|
||||
else:
|
||||
@ -240,7 +233,7 @@ class AjaxHandler(BaseHandler):
|
||||
<span style="margin-right: 6px;"><i class="far fa-file">
|
||||
</i></span></input>{filename}</li>"""
|
||||
|
||||
self.write(helper.get_os_understandable_path(folder) + "\n" + output)
|
||||
self.write(Helpers.get_os_understandable_path(folder) + "\n" + output)
|
||||
self.finish()
|
||||
|
||||
elif page == "get_dir":
|
||||
@ -252,13 +245,13 @@ class AjaxHandler(BaseHandler):
|
||||
else:
|
||||
server_id = bleach.clean(server_id)
|
||||
|
||||
if helper.validate_traversal(
|
||||
if Helpers.validate_traversal(
|
||||
self.controller.servers.get_server_data_by_id(server_id)["path"], path
|
||||
):
|
||||
self.write(
|
||||
helper.get_os_understandable_path(path)
|
||||
Helpers.get_os_understandable_path(path)
|
||||
+ "\n"
|
||||
+ helper.generate_dir(path)
|
||||
+ Helpers.generate_dir(path)
|
||||
)
|
||||
self.finish()
|
||||
|
||||
@ -272,14 +265,14 @@ class AjaxHandler(BaseHandler):
|
||||
server_id = self.get_argument("id", None)
|
||||
|
||||
permissions = {
|
||||
"Commands": Enum_Permissions_Server.Commands,
|
||||
"Terminal": Enum_Permissions_Server.Terminal,
|
||||
"Logs": Enum_Permissions_Server.Logs,
|
||||
"Schedule": Enum_Permissions_Server.Schedule,
|
||||
"Backup": Enum_Permissions_Server.Backup,
|
||||
"Files": Enum_Permissions_Server.Files,
|
||||
"Config": Enum_Permissions_Server.Config,
|
||||
"Players": Enum_Permissions_Server.Players,
|
||||
"Commands": EnumPermissionsServer.COMMANDS,
|
||||
"Terminal": EnumPermissionsServer.TERMINAL,
|
||||
"Logs": EnumPermissionsServer.LOGS,
|
||||
"Schedule": EnumPermissionsServer.SCHEDULE,
|
||||
"Backup": EnumPermissionsServer.BACKUP,
|
||||
"Files": EnumPermissionsServer.FILES,
|
||||
"Config": EnumPermissionsServer.CONFIG,
|
||||
"Players": EnumPermissionsServer.PLAYERS,
|
||||
}
|
||||
user_perms = self.controller.server_perms.get_user_id_permissions_list(
|
||||
exec_user["user_id"], server_id
|
||||
@ -291,7 +284,7 @@ class AjaxHandler(BaseHandler):
|
||||
|
||||
if server_id is None:
|
||||
logger.warning("Server ID not found in send_command ajax call")
|
||||
console.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.get_server_obj(server_id)
|
||||
|
||||
@ -390,11 +383,11 @@ class AjaxHandler(BaseHandler):
|
||||
server_data = self.controller.servers.get_server_data_by_id(server_id)
|
||||
if server_data["type"] == "minecraft-java":
|
||||
backup_path = svr_obj.backup_path
|
||||
if helper.validate_traversal(backup_path, zip_name):
|
||||
tempDir = helper.unzip_backup_archive(backup_path, zip_name)
|
||||
if Helpers.validate_traversal(backup_path, zip_name):
|
||||
temp_dir = Helpers.unzip_backup_archive(backup_path, zip_name)
|
||||
new_server = self.controller.import_zip_server(
|
||||
svr_obj.server_name,
|
||||
tempDir,
|
||||
temp_dir,
|
||||
server_data["executable"],
|
||||
"1",
|
||||
"2",
|
||||
@ -410,11 +403,11 @@ class AjaxHandler(BaseHandler):
|
||||
|
||||
else:
|
||||
backup_path = svr_obj.backup_path
|
||||
if helper.validate_traversal(backup_path, zip_name):
|
||||
tempDir = helper.unzip_backup_archive(backup_path, zip_name)
|
||||
if Helpers.validate_traversal(backup_path, zip_name):
|
||||
temp_dir = Helpers.unzip_backup_archive(backup_path, zip_name)
|
||||
new_server = self.controller.import_bedrock_zip_server(
|
||||
svr_obj.server_name,
|
||||
tempDir,
|
||||
temp_dir,
|
||||
server_data["executable"],
|
||||
server_data["server_port"],
|
||||
)
|
||||
@ -428,23 +421,27 @@ class AjaxHandler(BaseHandler):
|
||||
|
||||
elif page == "unzip_server":
|
||||
path = self.get_argument("path", None)
|
||||
if helper.check_file_exists(path):
|
||||
helper.unzipServer(path, exec_user["user_id"])
|
||||
if Helpers.check_file_exists(path):
|
||||
self.helper.unzip_server(path, exec_user["user_id"])
|
||||
else:
|
||||
user_id = exec_user["user_id"]
|
||||
if user_id:
|
||||
time.sleep(5)
|
||||
user_lang = self.controller.users.get_user_lang_by_id(user_id)
|
||||
websocket_helper.broadcast_user(
|
||||
self.helper.websocket_helper.broadcast_user(
|
||||
user_id,
|
||||
"send_start_error",
|
||||
{"error": translation.translate("error", "no-file", user_lang)},
|
||||
{
|
||||
"error": self.helper.translation.translate(
|
||||
"error", "no-file", user_lang
|
||||
)
|
||||
},
|
||||
)
|
||||
return
|
||||
|
||||
elif page == "backup_select":
|
||||
path = self.get_argument("path", None)
|
||||
helper.backup_select(path, exec_user["user_id"])
|
||||
self.helper.backup_select(path, exec_user["user_id"])
|
||||
return
|
||||
|
||||
@tornado.web.authenticated
|
||||
@ -457,14 +454,14 @@ class AjaxHandler(BaseHandler):
|
||||
server_id = self.get_argument("id", None)
|
||||
|
||||
permissions = {
|
||||
"Commands": Enum_Permissions_Server.Commands,
|
||||
"Terminal": Enum_Permissions_Server.Terminal,
|
||||
"Logs": Enum_Permissions_Server.Logs,
|
||||
"Schedule": Enum_Permissions_Server.Schedule,
|
||||
"Backup": Enum_Permissions_Server.Backup,
|
||||
"Files": Enum_Permissions_Server.Files,
|
||||
"Config": Enum_Permissions_Server.Config,
|
||||
"Players": Enum_Permissions_Server.Players,
|
||||
"Commands": EnumPermissionsServer.COMMANDS,
|
||||
"Terminal": EnumPermissionsServer.TERMINAL,
|
||||
"Logs": EnumPermissionsServer.LOGS,
|
||||
"Schedule": EnumPermissionsServer.SCHEDULE,
|
||||
"Backup": EnumPermissionsServer.BACKUP,
|
||||
"Files": EnumPermissionsServer.FILES,
|
||||
"Config": EnumPermissionsServer.CONFIG,
|
||||
"Players": EnumPermissionsServer.PLAYERS,
|
||||
}
|
||||
user_perms = self.controller.server_perms.get_user_id_permissions_list(
|
||||
exec_user["user_id"], server_id
|
||||
@ -481,12 +478,12 @@ class AjaxHandler(BaseHandler):
|
||||
if not superuser:
|
||||
self.redirect("/panel/error?error=Unauthorized access to Backups")
|
||||
return
|
||||
file_path = helper.get_os_understandable_path(
|
||||
file_path = Helpers.get_os_understandable_path(
|
||||
self.get_body_argument("file_path", default=None, strip=True)
|
||||
)
|
||||
server_id = self.get_argument("id", None)
|
||||
|
||||
console.warning(f"Delete {file_path} for server {server_id}")
|
||||
Console.warning(f"Delete {file_path} for server {server_id}")
|
||||
|
||||
if not self.check_server_id(server_id, "del_backup"):
|
||||
return
|
||||
@ -495,21 +492,22 @@ class AjaxHandler(BaseHandler):
|
||||
|
||||
server_info = self.controller.servers.get_server_data_by_id(server_id)
|
||||
if not (
|
||||
helper.in_path(
|
||||
helper.get_os_understandable_path(server_info["path"]), file_path
|
||||
Helpers.in_path(
|
||||
Helpers.get_os_understandable_path(server_info["path"]), file_path
|
||||
)
|
||||
or helper.in_path(
|
||||
helper.get_os_understandable_path(server_info["backup_path"]),
|
||||
or Helpers.in_path(
|
||||
Helpers.get_os_understandable_path(server_info["backup_path"]),
|
||||
file_path,
|
||||
)
|
||||
) or not helper.check_file_exists(os.path.abspath(file_path)):
|
||||
) or not Helpers.check_file_exists(os.path.abspath(file_path)):
|
||||
logger.warning(f"Invalid path in del_backup ajax call ({file_path})")
|
||||
console.warning(f"Invalid path in del_backup ajax call ({file_path})")
|
||||
Console.warning(f"Invalid path in del_backup ajax call ({file_path})")
|
||||
return
|
||||
|
||||
# Delete the file
|
||||
if helper.validate_traversal(
|
||||
helper.get_os_understandable_path(server_info["backup_path"]), file_path
|
||||
if Helpers.validate_traversal(
|
||||
Helpers.get_os_understandable_path(server_info["backup_path"]),
|
||||
file_path,
|
||||
):
|
||||
os.remove(file_path)
|
||||
|
||||
@ -566,7 +564,7 @@ class AjaxHandler(BaseHandler):
|
||||
logger.warning(
|
||||
f"Server ID not defined in {page_name} ajax call ({server_id})"
|
||||
)
|
||||
console.warning(
|
||||
Console.warning(
|
||||
f"Server ID not defined in {page_name} ajax call ({server_id})"
|
||||
)
|
||||
return
|
||||
@ -578,7 +576,7 @@ class AjaxHandler(BaseHandler):
|
||||
logger.warning(
|
||||
f"Server ID not found in {page_name} ajax call ({server_id})"
|
||||
)
|
||||
console.warning(
|
||||
Console.warning(
|
||||
f"Server ID not found in {page_name} ajax call ({server_id})"
|
||||
)
|
||||
return
|
||||
|
@ -1,6 +1,9 @@
|
||||
from datetime import datetime
|
||||
import logging
|
||||
import re
|
||||
|
||||
from app.classes.controllers.crafty_perms_controller import EnumPermissionsCrafty
|
||||
from app.classes.controllers.server_perms_controller import EnumPermissionsServer
|
||||
from app.classes.web.base_handler import BaseHandler
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@ -13,6 +16,10 @@ class ApiHandler(BaseHandler):
|
||||
self.set_status(status)
|
||||
self.write(data)
|
||||
|
||||
def check_xsrf_cookie(self):
|
||||
# Disable CSRF protection on API routes
|
||||
pass
|
||||
|
||||
def access_denied(self, user, reason=""):
|
||||
if reason:
|
||||
reason = " because " + reason
|
||||
@ -34,10 +41,24 @@ class ApiHandler(BaseHandler):
|
||||
)
|
||||
|
||||
def authenticate_user(self) -> bool:
|
||||
self.permissions = {
|
||||
"Commands": EnumPermissionsServer.COMMANDS,
|
||||
"Terminal": EnumPermissionsServer.TERMINAL,
|
||||
"Logs": EnumPermissionsServer.LOGS,
|
||||
"Schedule": EnumPermissionsServer.SCHEDULE,
|
||||
"Backup": EnumPermissionsServer.BACKUP,
|
||||
"Files": EnumPermissionsServer.FILES,
|
||||
"Config": EnumPermissionsServer.CONFIG,
|
||||
"Players": EnumPermissionsServer.PLAYERS,
|
||||
"Server_Creation": EnumPermissionsCrafty.SERVER_CREATION,
|
||||
"User_Config": EnumPermissionsCrafty.USER_CONFIG,
|
||||
"Roles_Config": EnumPermissionsCrafty.ROLES_CONFIG,
|
||||
}
|
||||
try:
|
||||
logger.debug("Searching for specified token")
|
||||
|
||||
api_token = self.get_argument("token", "")
|
||||
self.api_token = api_token
|
||||
if api_token is None and self.request.headers.get("Authorization"):
|
||||
api_token = bearer_pattern.sub(
|
||||
"", self.request.headers.get("Authorization")
|
||||
@ -50,7 +71,6 @@ class ApiHandler(BaseHandler):
|
||||
if user_data:
|
||||
# Login successful! Check perms
|
||||
logger.info(f"User {user_data['username']} has authenticated to API")
|
||||
# TODO: Role check
|
||||
|
||||
return True # This is to set the "authenticated"
|
||||
else:
|
||||
@ -75,12 +95,28 @@ class ServersStats(ApiHandler):
|
||||
def get(self):
|
||||
"""Get details about all servers"""
|
||||
authenticated = self.authenticate_user()
|
||||
user_obj = self.controller.users.get_user_by_api_token(self.api_token)
|
||||
if not authenticated:
|
||||
return
|
||||
if user_obj["superuser"]:
|
||||
raw_stats = self.controller.servers.get_all_servers_stats()
|
||||
else:
|
||||
raw_stats = self.controller.servers.get_authorized_servers_stats(
|
||||
user_obj["user_id"]
|
||||
)
|
||||
stats = []
|
||||
for rs in raw_stats:
|
||||
s = {}
|
||||
for k, v in rs["server_data"].items():
|
||||
if isinstance(v, datetime):
|
||||
s[k] = v.timestamp()
|
||||
else:
|
||||
s[k] = v
|
||||
stats.append(s)
|
||||
|
||||
# Get server stats
|
||||
# TODO Check perms
|
||||
self.finish(self.write({"servers": self.controller.stats.get_servers_stats()}))
|
||||
self.finish(self.write({"servers": stats}))
|
||||
|
||||
|
||||
class NodeStats(ApiHandler):
|
||||
@ -92,5 +128,311 @@ class NodeStats(ApiHandler):
|
||||
|
||||
# Get node stats
|
||||
node_stats = self.controller.stats.get_node_stats()
|
||||
node_stats.pop("servers")
|
||||
self.finish(self.write(node_stats))
|
||||
self.return_response(200, {"code": node_stats["node_stats"]})
|
||||
|
||||
|
||||
class SendCommand(ApiHandler):
|
||||
def post(self):
|
||||
user = self.authenticate_user()
|
||||
|
||||
user_obj = self.controller.users.get_user_by_api_token(self.api_token)
|
||||
|
||||
if user is None:
|
||||
self.access_denied("unknown")
|
||||
return
|
||||
server_id = self.get_argument("id")
|
||||
|
||||
if (
|
||||
not user_obj["user_id"]
|
||||
in self.controller.server_perms.get_server_user_list(server_id)
|
||||
and not user_obj["superuser"]
|
||||
):
|
||||
self.access_denied("unknown")
|
||||
return
|
||||
|
||||
if not self.permissions[
|
||||
"Commands"
|
||||
] in self.controller.server_perms.get_api_key_permissions_list(
|
||||
self.controller.users.get_api_key_by_token(self.api_token), server_id
|
||||
):
|
||||
self.access_denied(user)
|
||||
return
|
||||
|
||||
command = self.get_argument("command", default=None, strip=True)
|
||||
server_id = self.get_argument("id")
|
||||
if command:
|
||||
server = self.controller.get_server_obj(server_id)
|
||||
if server.check_running:
|
||||
server.send_command(command)
|
||||
self.return_response(200, {"run": True})
|
||||
else:
|
||||
self.return_response(200, {"error": "SER_NOT_RUNNING"})
|
||||
else:
|
||||
self.return_response(200, {"error": "NO_COMMAND"})
|
||||
|
||||
|
||||
class ServerBackup(ApiHandler):
|
||||
def post(self):
|
||||
user = self.authenticate_user()
|
||||
|
||||
user_obj = self.controller.users.get_user_by_api_token(self.api_token)
|
||||
|
||||
if user is None:
|
||||
self.access_denied("unknown")
|
||||
return
|
||||
server_id = self.get_argument("id")
|
||||
|
||||
if (
|
||||
not user_obj["user_id"]
|
||||
in self.controller.server_perms.get_server_user_list(server_id)
|
||||
and not user_obj["superuser"]
|
||||
):
|
||||
self.access_denied("unknown")
|
||||
return
|
||||
|
||||
if not self.permissions[
|
||||
"Backup"
|
||||
] in self.controller.server_perms.get_api_key_permissions_list(
|
||||
self.controller.users.get_api_key_by_token(self.api_token), server_id
|
||||
):
|
||||
self.access_denied(user)
|
||||
return
|
||||
|
||||
server = self.controller.get_server_obj(server_id)
|
||||
|
||||
server.backup_server()
|
||||
|
||||
self.return_response(200, {"code": "SER_BAK_CALLED"})
|
||||
|
||||
|
||||
class StartServer(ApiHandler):
|
||||
def post(self):
|
||||
user = self.authenticate_user()
|
||||
remote_ip = self.get_remote_ip()
|
||||
|
||||
user_obj = self.controller.users.get_user_by_api_token(self.api_token)
|
||||
|
||||
if user is None:
|
||||
self.access_denied("unknown")
|
||||
return
|
||||
server_id = self.get_argument("id")
|
||||
|
||||
if (
|
||||
not user_obj["user_id"]
|
||||
in self.controller.server_perms.get_server_user_list(server_id)
|
||||
and not user_obj["superuser"]
|
||||
):
|
||||
self.access_denied("unknown")
|
||||
return
|
||||
elif not self.permissions[
|
||||
"Commands"
|
||||
] in self.controller.server_perms.get_api_key_permissions_list(
|
||||
self.controller.users.get_api_key_by_token(self.api_token), server_id
|
||||
):
|
||||
self.access_denied("unknown")
|
||||
return
|
||||
|
||||
server = self.controller.get_server_obj(server_id)
|
||||
|
||||
if not server.check_running():
|
||||
self.controller.management.send_command(
|
||||
user_obj["user_id"], server_id, remote_ip, "start_server"
|
||||
)
|
||||
self.return_response(200, {"code": "SER_START_CALLED"})
|
||||
else:
|
||||
self.return_response(500, {"error": "SER_RUNNING"})
|
||||
|
||||
|
||||
class StopServer(ApiHandler):
|
||||
def post(self):
|
||||
user = self.authenticate_user()
|
||||
remote_ip = self.get_remote_ip()
|
||||
|
||||
user_obj = self.controller.users.get_user_by_api_token(self.api_token)
|
||||
|
||||
if user is None:
|
||||
self.access_denied("unknown")
|
||||
return
|
||||
server_id = self.get_argument("id")
|
||||
|
||||
if (
|
||||
not user_obj["user_id"]
|
||||
in self.controller.server_perms.get_server_user_list(server_id)
|
||||
and not user_obj["superuser"]
|
||||
):
|
||||
self.access_denied("unknown")
|
||||
|
||||
if not self.permissions[
|
||||
"Commands"
|
||||
] in self.controller.server_perms.get_api_key_permissions_list(
|
||||
self.controller.users.get_api_key_by_token(self.api_token), server_id
|
||||
):
|
||||
self.access_denied(user)
|
||||
return
|
||||
|
||||
server = self.controller.get_server_obj(server_id)
|
||||
|
||||
if server.check_running():
|
||||
self.controller.management.send_command(
|
||||
user, server_id, remote_ip, "stop_server"
|
||||
)
|
||||
|
||||
self.return_response(200, {"code": "SER_STOP_CALLED"})
|
||||
else:
|
||||
self.return_response(500, {"error": "SER_NOT_RUNNING"})
|
||||
|
||||
|
||||
class RestartServer(ApiHandler):
|
||||
def post(self):
|
||||
user = self.authenticate_user()
|
||||
remote_ip = self.get_remote_ip()
|
||||
user_obj = self.controller.users.get_user_by_api_token(self.api_token)
|
||||
|
||||
if user is None:
|
||||
self.access_denied("unknown")
|
||||
return
|
||||
server_id = self.get_argument("id")
|
||||
|
||||
if not user_obj["user_id"] in self.controller.server_perms.get_server_user_list(
|
||||
server_id
|
||||
):
|
||||
self.access_denied("unknown")
|
||||
|
||||
if not self.permissions[
|
||||
"Commands"
|
||||
] in self.controller.server_perms.get_api_key_permissions_list(
|
||||
self.controller.users.get_api_key_by_token(self.api_token), server_id
|
||||
):
|
||||
self.access_denied(user)
|
||||
|
||||
self.controller.management.send_command(
|
||||
user, server_id, remote_ip, "restart_server"
|
||||
)
|
||||
self.return_response(200, {"code": "SER_RESTART_CALLED"})
|
||||
|
||||
|
||||
class CreateUser(ApiHandler):
|
||||
def post(self):
|
||||
user = self.authenticate_user()
|
||||
user_obj = self.controller.users.get_user_by_api_token(self.api_token)
|
||||
|
||||
user_perms = self.controller.crafty_perms.get_crafty_permissions_list(
|
||||
user_obj["user_id"]
|
||||
)
|
||||
if (
|
||||
not self.permissions["User_Config"] in user_perms
|
||||
and not user_obj["superuser"]
|
||||
):
|
||||
self.access_denied("unknown")
|
||||
return
|
||||
|
||||
if user is None:
|
||||
self.access_denied("unknown")
|
||||
return
|
||||
|
||||
if not self.permissions[
|
||||
"User_Config"
|
||||
] in self.controller.crafty_perms.get_api_key_permissions_list(
|
||||
self.controller.users.get_api_key_by_token(self.api_token)
|
||||
):
|
||||
self.access_denied(user)
|
||||
return
|
||||
|
||||
new_username = self.get_argument("username")
|
||||
new_pass = self.get_argument("password")
|
||||
|
||||
if new_username:
|
||||
self.controller.users.add_user(
|
||||
new_username, new_pass, "default@example.com", True, False
|
||||
)
|
||||
|
||||
self.return_response(
|
||||
200,
|
||||
{
|
||||
"code": "COMPLETE",
|
||||
"username": new_username,
|
||||
"password": new_pass,
|
||||
},
|
||||
)
|
||||
else:
|
||||
self.return_response(
|
||||
500,
|
||||
{
|
||||
"error": "MISSING_PARAMS",
|
||||
"info": "Some paramaters failed validation",
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
class DeleteUser(ApiHandler):
|
||||
def post(self):
|
||||
user = self.authenticate_user()
|
||||
|
||||
user_obj = self.controller.users.get_user_by_api_token(self.api_token)
|
||||
|
||||
user_perms = self.controller.crafty_perms.get_crafty_permissions_list(
|
||||
user_obj["user_id"]
|
||||
)
|
||||
|
||||
if (
|
||||
not self.permissions["User_Config"] in user_perms
|
||||
and not user_obj["superuser"]
|
||||
):
|
||||
self.access_denied("unknown")
|
||||
return
|
||||
|
||||
if user is None:
|
||||
self.access_denied("unknown")
|
||||
return
|
||||
|
||||
if not self.permissions[
|
||||
"User_Config"
|
||||
] in self.controller.crafty_perms.get_api_key_permissions_list(
|
||||
self.controller.users.get_api_key_by_token(self.api_token)
|
||||
):
|
||||
self.access_denied(user)
|
||||
return
|
||||
|
||||
user_id = self.get_argument("user_id", None, True)
|
||||
user_to_del = self.controller.users.get_user_by_id(user_id)
|
||||
|
||||
if user_to_del["superuser"]:
|
||||
self.return_response(
|
||||
500,
|
||||
{"error": "NOT_ALLOWED", "info": "You cannot delete a super user"},
|
||||
)
|
||||
else:
|
||||
if user_id:
|
||||
self.controller.users.remove_user(user_id)
|
||||
self.return_response(200, {"code": "COMPLETED"})
|
||||
|
||||
|
||||
class ListServers(ApiHandler):
|
||||
def get(self):
|
||||
user = self.authenticate_user()
|
||||
user_obj = self.controller.users.get_user_by_api_token(self.api_token)
|
||||
|
||||
if user is None:
|
||||
self.access_denied("unknown")
|
||||
return
|
||||
|
||||
if self.api_token is None:
|
||||
self.access_denied("unknown")
|
||||
return
|
||||
|
||||
if user_obj["superuser"]:
|
||||
servers = self.controller.servers.get_all_defined_servers()
|
||||
servers = [str(i) for i in servers]
|
||||
else:
|
||||
servers = self.controller.servers.get_authorized_servers(
|
||||
user_obj["user_id"]
|
||||
)
|
||||
servers = [str(i) for i in servers]
|
||||
|
||||
self.return_response(
|
||||
200,
|
||||
{
|
||||
"code": "COMPLETED",
|
||||
"servers": servers,
|
||||
},
|
||||
)
|
||||
|
@ -1,17 +1,9 @@
|
||||
import logging
|
||||
from typing import Union, List, Optional, Tuple, Dict, Any
|
||||
import bleach
|
||||
import tornado.web
|
||||
|
||||
from app.classes.models.users import ApiKeys
|
||||
from app.classes.shared.authentication import authentication
|
||||
from app.classes.shared.main_controller import Controller
|
||||
from app.classes.shared.helpers import helper
|
||||
|
||||
try:
|
||||
import tornado.web
|
||||
import bleach
|
||||
|
||||
except ModuleNotFoundError as e:
|
||||
helper.auto_installer_fix(e)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@ -23,8 +15,9 @@ class BaseHandler(tornado.web.RequestHandler):
|
||||
|
||||
# noinspection PyAttributeOutsideInit
|
||||
def initialize(
|
||||
self, controller: Controller = None, tasks_manager=None, translator=None
|
||||
self, helper=None, controller=None, tasks_manager=None, translator=None
|
||||
):
|
||||
self.helper = helper
|
||||
self.controller = controller
|
||||
self.tasks_manager = tasks_manager
|
||||
self.translator = translator
|
||||
@ -42,7 +35,7 @@ class BaseHandler(tornado.web.RequestHandler):
|
||||
def get_current_user(
|
||||
self,
|
||||
) -> Optional[Tuple[Optional[ApiKeys], Dict[str, Any], Dict[str, Any]]]:
|
||||
return authentication.check(self.get_cookie("token"))
|
||||
return self.controller.authentication.check(self.get_cookie("token"))
|
||||
|
||||
def autobleach(self, name, text):
|
||||
for r in self.redactables:
|
||||
|
@ -8,8 +8,7 @@ logger = logging.getLogger(__name__)
|
||||
class DefaultHandler(BaseHandler):
|
||||
|
||||
# Override prepare() instead of get() to cover all possible HTTP methods.
|
||||
# pylint: disable=arguments-differ
|
||||
def prepare(self, page=None):
|
||||
def prepare(self, page=None): # pylint: disable=arguments-differ
|
||||
if page is not None:
|
||||
self.set_status(404)
|
||||
self.render(
|
||||
|
@ -1,20 +1,15 @@
|
||||
import os
|
||||
import logging
|
||||
import bleach
|
||||
import tornado.web
|
||||
import tornado.escape
|
||||
|
||||
from app.classes.models.server_permissions import Enum_Permissions_Server
|
||||
from app.classes.shared.console import console
|
||||
from app.classes.shared.helpers import helper
|
||||
from app.classes.shared.file_helpers import file_helper
|
||||
from app.classes.models.server_permissions import EnumPermissionsServer
|
||||
from app.classes.shared.console import Console
|
||||
from app.classes.shared.helpers import Helpers
|
||||
from app.classes.shared.file_helpers import FileHelpers
|
||||
from app.classes.web.base_handler import BaseHandler
|
||||
|
||||
try:
|
||||
import bleach
|
||||
import tornado.web
|
||||
import tornado.escape
|
||||
|
||||
except ModuleNotFoundError as e:
|
||||
helper.auto_installer_fix(e)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@ -36,14 +31,14 @@ class FileHandler(BaseHandler):
|
||||
server_id = self.get_argument("id", None)
|
||||
|
||||
permissions = {
|
||||
"Commands": Enum_Permissions_Server.Commands,
|
||||
"Terminal": Enum_Permissions_Server.Terminal,
|
||||
"Logs": Enum_Permissions_Server.Logs,
|
||||
"Schedule": Enum_Permissions_Server.Schedule,
|
||||
"Backup": Enum_Permissions_Server.Backup,
|
||||
"Files": Enum_Permissions_Server.Files,
|
||||
"Config": Enum_Permissions_Server.Config,
|
||||
"Players": Enum_Permissions_Server.Players,
|
||||
"Commands": EnumPermissionsServer.COMMANDS,
|
||||
"Terminal": EnumPermissionsServer.TERMINAL,
|
||||
"Logs": EnumPermissionsServer.LOGS,
|
||||
"Schedule": EnumPermissionsServer.SCHEDULE,
|
||||
"Backup": EnumPermissionsServer.BACKUP,
|
||||
"Files": EnumPermissionsServer.FILES,
|
||||
"Config": EnumPermissionsServer.CONFIG,
|
||||
"Players": EnumPermissionsServer.PLAYERS,
|
||||
}
|
||||
user_perms = self.controller.server_perms.get_user_id_permissions_list(
|
||||
exec_user["user_id"], server_id
|
||||
@ -54,7 +49,7 @@ class FileHandler(BaseHandler):
|
||||
if not superuser:
|
||||
self.redirect("/panel/error?error=Unauthorized access to Files")
|
||||
return
|
||||
file_path = helper.get_os_understandable_path(
|
||||
file_path = Helpers.get_os_understandable_path(
|
||||
self.get_argument("file_path", None)
|
||||
)
|
||||
|
||||
@ -63,16 +58,16 @@ class FileHandler(BaseHandler):
|
||||
else:
|
||||
server_id = bleach.clean(server_id)
|
||||
|
||||
if not helper.in_path(
|
||||
helper.get_os_understandable_path(
|
||||
if not Helpers.in_path(
|
||||
Helpers.get_os_understandable_path(
|
||||
self.controller.servers.get_server_data_by_id(server_id)["path"]
|
||||
),
|
||||
file_path,
|
||||
) or not helper.check_file_exists(os.path.abspath(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})"
|
||||
)
|
||||
console.warning(
|
||||
Console.warning(
|
||||
f"Invalid path in get_file file file ajax call ({file_path})"
|
||||
)
|
||||
return
|
||||
@ -101,13 +96,13 @@ class FileHandler(BaseHandler):
|
||||
else:
|
||||
server_id = bleach.clean(server_id)
|
||||
|
||||
if helper.validate_traversal(
|
||||
if Helpers.validate_traversal(
|
||||
self.controller.servers.get_server_data_by_id(server_id)["path"], path
|
||||
):
|
||||
self.write(
|
||||
helper.get_os_understandable_path(path)
|
||||
Helpers.get_os_understandable_path(path)
|
||||
+ "\n"
|
||||
+ helper.generate_tree(path)
|
||||
+ Helpers.generate_tree(path)
|
||||
)
|
||||
self.finish()
|
||||
|
||||
@ -123,13 +118,13 @@ class FileHandler(BaseHandler):
|
||||
else:
|
||||
server_id = bleach.clean(server_id)
|
||||
|
||||
if helper.validate_traversal(
|
||||
if Helpers.validate_traversal(
|
||||
self.controller.servers.get_server_data_by_id(server_id)["path"], path
|
||||
):
|
||||
self.write(
|
||||
helper.get_os_understandable_path(path)
|
||||
Helpers.get_os_understandable_path(path)
|
||||
+ "\n"
|
||||
+ helper.generate_dir(path)
|
||||
+ Helpers.generate_dir(path)
|
||||
)
|
||||
self.finish()
|
||||
|
||||
@ -143,14 +138,14 @@ class FileHandler(BaseHandler):
|
||||
server_id = self.get_argument("id", None)
|
||||
|
||||
permissions = {
|
||||
"Commands": Enum_Permissions_Server.Commands,
|
||||
"Terminal": Enum_Permissions_Server.Terminal,
|
||||
"Logs": Enum_Permissions_Server.Logs,
|
||||
"Schedule": Enum_Permissions_Server.Schedule,
|
||||
"Backup": Enum_Permissions_Server.Backup,
|
||||
"Files": Enum_Permissions_Server.Files,
|
||||
"Config": Enum_Permissions_Server.Config,
|
||||
"Players": Enum_Permissions_Server.Players,
|
||||
"Commands": EnumPermissionsServer.COMMANDS,
|
||||
"Terminal": EnumPermissionsServer.TERMINAL,
|
||||
"Logs": EnumPermissionsServer.LOGS,
|
||||
"Schedule": EnumPermissionsServer.SCHEDULE,
|
||||
"Backup": EnumPermissionsServer.BACKUP,
|
||||
"Files": EnumPermissionsServer.FILES,
|
||||
"Config": EnumPermissionsServer.CONFIG,
|
||||
"Players": EnumPermissionsServer.PLAYERS,
|
||||
}
|
||||
user_perms = self.controller.server_perms.get_user_id_permissions_list(
|
||||
exec_user["user_id"], server_id
|
||||
@ -161,7 +156,7 @@ class FileHandler(BaseHandler):
|
||||
if not superuser:
|
||||
self.redirect("/panel/error?error=Unauthorized access to Files")
|
||||
return
|
||||
file_parent = helper.get_os_understandable_path(
|
||||
file_parent = Helpers.get_os_understandable_path(
|
||||
self.get_body_argument("file_parent", default=None, strip=True)
|
||||
)
|
||||
file_name = self.get_body_argument("file_name", default=None, strip=True)
|
||||
@ -172,16 +167,16 @@ class FileHandler(BaseHandler):
|
||||
else:
|
||||
server_id = bleach.clean(server_id)
|
||||
|
||||
if not helper.in_path(
|
||||
helper.get_os_understandable_path(
|
||||
if not Helpers.in_path(
|
||||
Helpers.get_os_understandable_path(
|
||||
self.controller.servers.get_server_data_by_id(server_id)["path"]
|
||||
),
|
||||
file_path,
|
||||
) or helper.check_file_exists(os.path.abspath(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})"
|
||||
)
|
||||
console.warning(
|
||||
Console.warning(
|
||||
f"Invalid path in create_file file ajax call ({file_path})"
|
||||
)
|
||||
return
|
||||
@ -195,7 +190,7 @@ class FileHandler(BaseHandler):
|
||||
if not superuser:
|
||||
self.redirect("/panel/error?error=Unauthorized access to Files")
|
||||
return
|
||||
dir_parent = helper.get_os_understandable_path(
|
||||
dir_parent = Helpers.get_os_understandable_path(
|
||||
self.get_body_argument("dir_parent", default=None, strip=True)
|
||||
)
|
||||
dir_name = self.get_body_argument("dir_name", default=None, strip=True)
|
||||
@ -206,16 +201,16 @@ class FileHandler(BaseHandler):
|
||||
else:
|
||||
server_id = bleach.clean(server_id)
|
||||
|
||||
if not helper.in_path(
|
||||
helper.get_os_understandable_path(
|
||||
if not Helpers.in_path(
|
||||
Helpers.get_os_understandable_path(
|
||||
self.controller.servers.get_server_data_by_id(server_id)["path"]
|
||||
),
|
||||
dir_path,
|
||||
) or helper.check_path_exists(os.path.abspath(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})"
|
||||
)
|
||||
console.warning(
|
||||
Console.warning(
|
||||
f"Invalid path in create_dir file ajax call ({dir_path})"
|
||||
)
|
||||
return
|
||||
@ -227,8 +222,8 @@ class FileHandler(BaseHandler):
|
||||
if not superuser:
|
||||
self.redirect("/panel/error?error=Unauthorized access to Files")
|
||||
return
|
||||
path = helper.get_os_understandable_path(self.get_argument("path", None))
|
||||
helper.unzipFile(path)
|
||||
path = Helpers.get_os_understandable_path(self.get_argument("path", None))
|
||||
Helpers.unzip_file(path)
|
||||
self.redirect(f"/panel/server_detail?id={server_id}&subpage=files")
|
||||
return
|
||||
|
||||
@ -242,14 +237,14 @@ class FileHandler(BaseHandler):
|
||||
server_id = self.get_argument("id", None)
|
||||
|
||||
permissions = {
|
||||
"Commands": Enum_Permissions_Server.Commands,
|
||||
"Terminal": Enum_Permissions_Server.Terminal,
|
||||
"Logs": Enum_Permissions_Server.Logs,
|
||||
"Schedule": Enum_Permissions_Server.Schedule,
|
||||
"Backup": Enum_Permissions_Server.Backup,
|
||||
"Files": Enum_Permissions_Server.Files,
|
||||
"Config": Enum_Permissions_Server.Config,
|
||||
"Players": Enum_Permissions_Server.Players,
|
||||
"Commands": EnumPermissionsServer.COMMANDS,
|
||||
"Terminal": EnumPermissionsServer.TERMINAL,
|
||||
"Logs": EnumPermissionsServer.LOGS,
|
||||
"Schedule": EnumPermissionsServer.SCHEDULE,
|
||||
"Backup": EnumPermissionsServer.BACKUP,
|
||||
"Files": EnumPermissionsServer.FILES,
|
||||
"Config": EnumPermissionsServer.CONFIG,
|
||||
"Players": EnumPermissionsServer.PLAYERS,
|
||||
}
|
||||
user_perms = self.controller.server_perms.get_user_id_permissions_list(
|
||||
exec_user["user_id"], server_id
|
||||
@ -259,11 +254,11 @@ class FileHandler(BaseHandler):
|
||||
if not superuser:
|
||||
self.redirect("/panel/error?error=Unauthorized access to Files")
|
||||
return
|
||||
file_path = helper.get_os_understandable_path(
|
||||
file_path = Helpers.get_os_understandable_path(
|
||||
self.get_body_argument("file_path", default=None, strip=True)
|
||||
)
|
||||
|
||||
console.warning(f"Delete {file_path} for server {server_id}")
|
||||
Console.warning(f"Delete {file_path} for server {server_id}")
|
||||
|
||||
if not self.check_server_id(server_id, "del_file"):
|
||||
return
|
||||
@ -272,33 +267,33 @@ class FileHandler(BaseHandler):
|
||||
|
||||
server_info = self.controller.servers.get_server_data_by_id(server_id)
|
||||
if not (
|
||||
helper.in_path(
|
||||
helper.get_os_understandable_path(server_info["path"]), file_path
|
||||
Helpers.in_path(
|
||||
Helpers.get_os_understandable_path(server_info["path"]), file_path
|
||||
)
|
||||
or helper.in_path(
|
||||
helper.get_os_understandable_path(server_info["backup_path"]),
|
||||
or Helpers.in_path(
|
||||
Helpers.get_os_understandable_path(server_info["backup_path"]),
|
||||
file_path,
|
||||
)
|
||||
) or not helper.check_file_exists(os.path.abspath(file_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})")
|
||||
console.warning(
|
||||
Console.warning(
|
||||
f"Invalid path in del_file file ajax call ({file_path})"
|
||||
)
|
||||
return
|
||||
|
||||
# Delete the file
|
||||
file_helper.del_file(file_path)
|
||||
FileHelpers.del_file(file_path)
|
||||
|
||||
elif page == "del_dir":
|
||||
if not permissions["Files"] in user_perms:
|
||||
if not superuser:
|
||||
self.redirect("/panel/error?error=Unauthorized access to Files")
|
||||
return
|
||||
dir_path = helper.get_os_understandable_path(
|
||||
dir_path = Helpers.get_os_understandable_path(
|
||||
self.get_body_argument("dir_path", default=None, strip=True)
|
||||
)
|
||||
|
||||
console.warning(f"Delete {dir_path} for server {server_id}")
|
||||
Console.warning(f"Delete {dir_path} for server {server_id}")
|
||||
|
||||
if not self.check_server_id(server_id, "del_dir"):
|
||||
return
|
||||
@ -306,20 +301,20 @@ class FileHandler(BaseHandler):
|
||||
server_id = bleach.clean(server_id)
|
||||
|
||||
server_info = self.controller.servers.get_server_data_by_id(server_id)
|
||||
if not helper.in_path(
|
||||
helper.get_os_understandable_path(server_info["path"]), dir_path
|
||||
) or not helper.check_path_exists(os.path.abspath(dir_path)):
|
||||
if not Helpers.in_path(
|
||||
Helpers.get_os_understandable_path(server_info["path"]), dir_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})")
|
||||
Console.warning(f"Invalid path in del_file file ajax call ({dir_path})")
|
||||
return
|
||||
|
||||
# Delete the directory
|
||||
# os.rmdir(dir_path) # Would only remove empty directories
|
||||
if helper.validate_traversal(
|
||||
helper.get_os_understandable_path(server_info["path"]), dir_path
|
||||
if Helpers.validate_traversal(
|
||||
Helpers.get_os_understandable_path(server_info["path"]), dir_path
|
||||
):
|
||||
# Removes also when there are contents
|
||||
file_helper.del_dirs(dir_path)
|
||||
FileHelpers.del_dirs(dir_path)
|
||||
|
||||
@tornado.web.authenticated
|
||||
def put(self, page):
|
||||
@ -330,14 +325,14 @@ class FileHandler(BaseHandler):
|
||||
|
||||
server_id = self.get_argument("id", None)
|
||||
permissions = {
|
||||
"Commands": Enum_Permissions_Server.Commands,
|
||||
"Terminal": Enum_Permissions_Server.Terminal,
|
||||
"Logs": Enum_Permissions_Server.Logs,
|
||||
"Schedule": Enum_Permissions_Server.Schedule,
|
||||
"Backup": Enum_Permissions_Server.Backup,
|
||||
"Files": Enum_Permissions_Server.Files,
|
||||
"Config": Enum_Permissions_Server.Config,
|
||||
"Players": Enum_Permissions_Server.Players,
|
||||
"Commands": EnumPermissionsServer.COMMANDS,
|
||||
"Terminal": EnumPermissionsServer.TERMINAL,
|
||||
"Logs": EnumPermissionsServer.LOGS,
|
||||
"Schedule": EnumPermissionsServer.SCHEDULE,
|
||||
"Backup": EnumPermissionsServer.BACKUP,
|
||||
"Files": EnumPermissionsServer.FILES,
|
||||
"Config": EnumPermissionsServer.CONFIG,
|
||||
"Players": EnumPermissionsServer.PLAYERS,
|
||||
}
|
||||
user_perms = self.controller.server_perms.get_user_id_permissions_list(
|
||||
exec_user["user_id"], server_id
|
||||
@ -350,7 +345,7 @@ class FileHandler(BaseHandler):
|
||||
file_contents = self.get_body_argument(
|
||||
"file_contents", default=None, strip=True
|
||||
)
|
||||
file_path = helper.get_os_understandable_path(
|
||||
file_path = Helpers.get_os_understandable_path(
|
||||
self.get_body_argument("file_path", default=None, strip=True)
|
||||
)
|
||||
|
||||
@ -359,16 +354,16 @@ class FileHandler(BaseHandler):
|
||||
else:
|
||||
server_id = bleach.clean(server_id)
|
||||
|
||||
if not helper.in_path(
|
||||
helper.get_os_understandable_path(
|
||||
if not Helpers.in_path(
|
||||
Helpers.get_os_understandable_path(
|
||||
self.controller.servers.get_server_data_by_id(server_id)["path"]
|
||||
),
|
||||
file_path,
|
||||
) or not helper.check_file_exists(os.path.abspath(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})"
|
||||
)
|
||||
console.warning(
|
||||
Console.warning(
|
||||
f"Invalid path in save_file file ajax call ({file_path})"
|
||||
)
|
||||
return
|
||||
@ -382,7 +377,7 @@ class FileHandler(BaseHandler):
|
||||
if not superuser:
|
||||
self.redirect("/panel/error?error=Unauthorized access to Files")
|
||||
return
|
||||
item_path = helper.get_os_understandable_path(
|
||||
item_path = Helpers.get_os_understandable_path(
|
||||
self.get_body_argument("item_path", default=None, strip=True)
|
||||
)
|
||||
new_item_name = self.get_body_argument(
|
||||
@ -396,35 +391,35 @@ class FileHandler(BaseHandler):
|
||||
|
||||
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")
|
||||
Console.warning("Invalid path(s) in rename_file file ajax call")
|
||||
return
|
||||
|
||||
if not helper.in_path(
|
||||
helper.get_os_understandable_path(
|
||||
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 helper.check_path_exists(os.path.abspath(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(
|
||||
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 helper.in_path(
|
||||
helper.get_os_understandable_path(
|
||||
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 helper.check_path_exists(os.path.abspath(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(
|
||||
Console.warning(
|
||||
f"Invalid new name path in rename_file file ajax call ({server_id})"
|
||||
)
|
||||
return
|
||||
@ -441,14 +436,14 @@ class FileHandler(BaseHandler):
|
||||
|
||||
server_id = self.get_argument("id", None)
|
||||
permissions = {
|
||||
"Commands": Enum_Permissions_Server.Commands,
|
||||
"Terminal": Enum_Permissions_Server.Terminal,
|
||||
"Logs": Enum_Permissions_Server.Logs,
|
||||
"Schedule": Enum_Permissions_Server.Schedule,
|
||||
"Backup": Enum_Permissions_Server.Backup,
|
||||
"Files": Enum_Permissions_Server.Files,
|
||||
"Config": Enum_Permissions_Server.Config,
|
||||
"Players": Enum_Permissions_Server.Players,
|
||||
"Commands": EnumPermissionsServer.COMMANDS,
|
||||
"Terminal": EnumPermissionsServer.TERMINAL,
|
||||
"Logs": EnumPermissionsServer.LOGS,
|
||||
"Schedule": EnumPermissionsServer.SCHEDULE,
|
||||
"Backup": EnumPermissionsServer.BACKUP,
|
||||
"Files": EnumPermissionsServer.FILES,
|
||||
"Config": EnumPermissionsServer.CONFIG,
|
||||
"Players": EnumPermissionsServer.PLAYERS,
|
||||
}
|
||||
user_perms = self.controller.server_perms.get_user_id_permissions_list(
|
||||
exec_user["user_id"], server_id
|
||||
@ -458,7 +453,7 @@ class FileHandler(BaseHandler):
|
||||
if not superuser:
|
||||
self.redirect("/panel/error?error=Unauthorized access to Files")
|
||||
return
|
||||
item_path = helper.get_os_understandable_path(
|
||||
item_path = Helpers.get_os_understandable_path(
|
||||
self.get_body_argument("item_path", default=None, strip=True)
|
||||
)
|
||||
new_item_name = self.get_body_argument(
|
||||
@ -472,35 +467,35 @@ class FileHandler(BaseHandler):
|
||||
|
||||
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")
|
||||
Console.warning("Invalid path(s) in rename_file file ajax call")
|
||||
return
|
||||
|
||||
if not helper.in_path(
|
||||
helper.get_os_understandable_path(
|
||||
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 helper.check_path_exists(os.path.abspath(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(
|
||||
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 helper.in_path(
|
||||
helper.get_os_understandable_path(
|
||||
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 helper.check_path_exists(os.path.abspath(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(
|
||||
Console.warning(
|
||||
f"Invalid new name path in rename_file file ajax call ({server_id})"
|
||||
)
|
||||
return
|
||||
@ -513,7 +508,7 @@ class FileHandler(BaseHandler):
|
||||
logger.warning(
|
||||
f"Server ID not defined in {page_name} file ajax call ({server_id})"
|
||||
)
|
||||
console.warning(
|
||||
Console.warning(
|
||||
f"Server ID not defined in {page_name} file ajax call ({server_id})"
|
||||
)
|
||||
return
|
||||
@ -525,7 +520,7 @@ class FileHandler(BaseHandler):
|
||||
logger.warning(
|
||||
f"Server ID not found in {page_name} file ajax call ({server_id})"
|
||||
)
|
||||
console.warning(
|
||||
Console.warning(
|
||||
f"Server ID not found in {page_name} file ajax call ({server_id})"
|
||||
)
|
||||
return
|
||||
|
@ -1,14 +1,8 @@
|
||||
import logging
|
||||
import requests
|
||||
|
||||
from app.classes.shared.helpers import helper
|
||||
from app.classes.web.base_handler import BaseHandler
|
||||
|
||||
try:
|
||||
import requests
|
||||
|
||||
except ModuleNotFoundError as e:
|
||||
helper.auto_installer_fix(e)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@ -21,7 +15,7 @@ class HTTPHandler(BaseHandler):
|
||||
url = "https://" + url_list[0]
|
||||
else:
|
||||
url = "https://" + url
|
||||
db_port = helper.get_setting("https_port")
|
||||
db_port = self.helper.get_setting("https_port")
|
||||
try:
|
||||
resp = requests.get(url + ":" + str(port))
|
||||
resp.raise_for_status()
|
||||
@ -39,7 +33,7 @@ class HTTPHandlerPage(BaseHandler):
|
||||
url = "https://" + url_list[0]
|
||||
else:
|
||||
url = "https://" + url
|
||||
db_port = helper.get_setting("https_port")
|
||||
db_port = self.helper.get_setting("https_port")
|
||||
try:
|
||||
resp = requests.get(url + ":" + str(port))
|
||||
resp.raise_for_status()
|
||||
|
@ -1,7 +1,5 @@
|
||||
import logging
|
||||
import requests
|
||||
|
||||
from app.classes.shared.helpers import helper
|
||||
from app.classes.web.base_handler import BaseHandler
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@ -16,13 +14,15 @@ class HTTPHandlerPage(BaseHandler):
|
||||
url_list = url.split("/")
|
||||
if url_list[0] != "":
|
||||
primary_url = url_list[0] + ":" + str(port) + "/"
|
||||
backup_url = url_list[0] + ":" + str(helper.get_setting("https_port")) + "/"
|
||||
backup_url = (
|
||||
url_list[0] + ":" + str(self.helper.get_setting("https_port")) + "/"
|
||||
)
|
||||
for i in range(len(url_list) - 1):
|
||||
primary_url += url_list[i + 1]
|
||||
backup_url += url_list[i + 1]
|
||||
else:
|
||||
primary_url = url + str(port)
|
||||
backup_url = url + str(helper.get_setting("https_port"))
|
||||
backup_url = url + str(self.helper.get_setting("https_port"))
|
||||
|
||||
try:
|
||||
resp = requests.get(primary_url)
|
||||
|
@ -6,29 +6,23 @@ from typing import Dict, Any, Tuple
|
||||
import json
|
||||
import logging
|
||||
import threading
|
||||
import bleach
|
||||
import libgravatar
|
||||
import requests
|
||||
import tornado.web
|
||||
import tornado.escape
|
||||
from tornado import iostream
|
||||
|
||||
from app.classes.models.server_permissions import Enum_Permissions_Server
|
||||
from app.classes.models.crafty_permissions import Enum_Permissions_Crafty
|
||||
from app.classes.models.management import management_helper
|
||||
from app.classes.shared.authentication import authentication
|
||||
from app.classes.shared.helpers import helper
|
||||
# TZLocal is set as a hidden import on win pipeline
|
||||
from tzlocal import get_localzone
|
||||
from cron_validator import CronValidator
|
||||
|
||||
from app.classes.models.server_permissions import EnumPermissionsServer
|
||||
from app.classes.models.crafty_permissions import EnumPermissionsCrafty
|
||||
from app.classes.models.management import HelpersManagement
|
||||
from app.classes.shared.helpers import Helpers
|
||||
from app.classes.web.base_handler import BaseHandler
|
||||
|
||||
try:
|
||||
import bleach
|
||||
import libgravatar
|
||||
import requests
|
||||
import tornado.web
|
||||
import tornado.escape
|
||||
from tornado import iostream
|
||||
|
||||
# TZLocal is set as a hidden import on win pipeline
|
||||
from tzlocal import get_localzone
|
||||
from cron_validator import CronValidator
|
||||
|
||||
except ModuleNotFoundError as ex:
|
||||
helper.auto_installer_fix(ex)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@ -191,10 +185,10 @@ class PanelHandler(BaseHandler):
|
||||
)
|
||||
page_data["num_players"] = total_players
|
||||
|
||||
for s in page_data["servers"]:
|
||||
for server in page_data["servers"]:
|
||||
try:
|
||||
data = json.loads(s["int_ping_results"])
|
||||
s["int_ping_results"] = data
|
||||
data = json.loads(server["int_ping_results"])
|
||||
server["int_ping_results"] = data
|
||||
except Exception as e:
|
||||
logger.error(f"Failed server data for page with error: {e}")
|
||||
|
||||
@ -268,14 +262,14 @@ class PanelHandler(BaseHandler):
|
||||
# todo: make this actually pull and compare version data
|
||||
"update_available": False,
|
||||
"serverTZ": get_localzone(),
|
||||
"version_data": helper.get_version_string(),
|
||||
"version_data": self.helper.get_version_string(),
|
||||
"user_data": exec_user,
|
||||
"user_role": exec_user_role,
|
||||
"user_crafty_permissions": exec_user_crafty_permissions,
|
||||
"crafty_permissions": {
|
||||
"Server_Creation": Enum_Permissions_Crafty.Server_Creation,
|
||||
"User_Config": Enum_Permissions_Crafty.User_Config,
|
||||
"Roles_Config": Enum_Permissions_Crafty.Roles_Config,
|
||||
"Server_Creation": EnumPermissionsCrafty.SERVER_CREATION,
|
||||
"User_Config": EnumPermissionsCrafty.USER_CONFIG,
|
||||
"Roles_Config": EnumPermissionsCrafty.ROLES_CONFIG,
|
||||
},
|
||||
"server_stats": {
|
||||
"total": len(defined_servers),
|
||||
@ -287,11 +281,11 @@ class PanelHandler(BaseHandler):
|
||||
},
|
||||
"menu_servers": defined_servers,
|
||||
"hosts_data": self.controller.management.get_latest_hosts_stats(),
|
||||
"show_contribute": helper.get_setting("show_contribute_link", True),
|
||||
"show_contribute": self.helper.get_setting("show_contribute_link", True),
|
||||
"error": error,
|
||||
"time": formatted_time,
|
||||
"lang": self.controller.users.get_user_lang_by_id(exec_user["user_id"]),
|
||||
"lang_page": helper.getLangPage(
|
||||
"lang_page": Helpers.get_lang_page(
|
||||
self.controller.users.get_user_lang_by_id(exec_user["user_id"])
|
||||
),
|
||||
"super_user": superuser,
|
||||
@ -306,15 +300,17 @@ class PanelHandler(BaseHandler):
|
||||
else None,
|
||||
"superuser": superuser,
|
||||
}
|
||||
if helper.get_setting("allow_nsfw_profile_pictures"):
|
||||
if self.helper.get_setting("allow_nsfw_profile_pictures"):
|
||||
rating = "x"
|
||||
else:
|
||||
rating = "g"
|
||||
|
||||
# Get grvatar hash for profile pictures
|
||||
if exec_user["email"] != "default@example.com" or "":
|
||||
g = libgravatar.Gravatar(libgravatar.sanitize_email(exec_user["email"]))
|
||||
url = g.get_image(
|
||||
gravatar = libgravatar.Gravatar(
|
||||
libgravatar.sanitize_email(exec_user["email"])
|
||||
)
|
||||
url = gravatar.get_image(
|
||||
size=80,
|
||||
default="404",
|
||||
force_default=False,
|
||||
@ -322,9 +318,12 @@ class PanelHandler(BaseHandler):
|
||||
filetype_extension=False,
|
||||
use_ssl=True,
|
||||
) # + "?d=404"
|
||||
if requests.head(url).status_code != 404:
|
||||
profile_url = url
|
||||
else:
|
||||
try:
|
||||
if requests.head(url).status_code != 404:
|
||||
profile_url = url
|
||||
else:
|
||||
profile_url = "/static/assets/images/faces-clipart/pic-3.png"
|
||||
except:
|
||||
profile_url = "/static/assets/images/faces-clipart/pic-3.png"
|
||||
else:
|
||||
profile_url = "/static/assets/images/faces-clipart/pic-3.png"
|
||||
@ -338,7 +337,9 @@ class PanelHandler(BaseHandler):
|
||||
template = "public/error.html"
|
||||
|
||||
elif page == "credits":
|
||||
with open(helper.credits_cache, encoding="utf-8") as credits_default_local:
|
||||
with open(
|
||||
self.helper.credits_cache, encoding="utf-8"
|
||||
) as credits_default_local:
|
||||
try:
|
||||
remote = requests.get(
|
||||
"https://craftycontrol.com/credits", allow_redirects=True
|
||||
@ -499,14 +500,14 @@ class PanelHandler(BaseHandler):
|
||||
)
|
||||
page_data["active_link"] = subpage
|
||||
page_data["permissions"] = {
|
||||
"Commands": Enum_Permissions_Server.Commands,
|
||||
"Terminal": Enum_Permissions_Server.Terminal,
|
||||
"Logs": Enum_Permissions_Server.Logs,
|
||||
"Schedule": Enum_Permissions_Server.Schedule,
|
||||
"Backup": Enum_Permissions_Server.Backup,
|
||||
"Files": Enum_Permissions_Server.Files,
|
||||
"Config": Enum_Permissions_Server.Config,
|
||||
"Players": Enum_Permissions_Server.Players,
|
||||
"Commands": EnumPermissionsServer.COMMANDS,
|
||||
"Terminal": EnumPermissionsServer.TERMINAL,
|
||||
"Logs": EnumPermissionsServer.LOGS,
|
||||
"Schedule": EnumPermissionsServer.SCHEDULE,
|
||||
"Backup": EnumPermissionsServer.BACKUP,
|
||||
"Files": EnumPermissionsServer.FILES,
|
||||
"Config": EnumPermissionsServer.CONFIG,
|
||||
"Players": EnumPermissionsServer.PLAYERS,
|
||||
}
|
||||
page_data[
|
||||
"user_permissions"
|
||||
@ -582,7 +583,7 @@ class PanelHandler(BaseHandler):
|
||||
"/panel/error?error=Unauthorized access To Schedules"
|
||||
)
|
||||
return
|
||||
page_data["schedules"] = management_helper.get_schedules_by_server(
|
||||
page_data["schedules"] = HelpersManagement.get_schedules_by_server(
|
||||
server_id
|
||||
)
|
||||
|
||||
@ -632,7 +633,7 @@ class PanelHandler(BaseHandler):
|
||||
).send_backup_status()
|
||||
# makes it so relative path is the only thing shown
|
||||
for file in page_data["exclusions"]:
|
||||
if helper.is_os_windows():
|
||||
if Helpers.is_os_windows():
|
||||
exclusions.append(file.replace(server_info["path"] + "\\", ""))
|
||||
else:
|
||||
exclusions.append(file.replace(server_info["path"] + "/", ""))
|
||||
@ -642,7 +643,7 @@ class PanelHandler(BaseHandler):
|
||||
page_data["backup_list"] = server.list_backups()
|
||||
except:
|
||||
page_data["backup_list"] = []
|
||||
page_data["backup_path"] = helper.wtol_path(server_info["backup_path"])
|
||||
page_data["backup_path"] = Helpers.wtol_path(server_info["backup_path"])
|
||||
|
||||
def get_banned_players_html():
|
||||
banned_players = self.controller.servers.get_banned_players(server_id)
|
||||
@ -685,11 +686,11 @@ class PanelHandler(BaseHandler):
|
||||
server_info = self.controller.servers.get_server_data_by_id(server_id)
|
||||
backup_file = os.path.abspath(
|
||||
os.path.join(
|
||||
helper.get_os_understandable_path(server_info["backup_path"]), file
|
||||
Helpers.get_os_understandable_path(server_info["backup_path"]), file
|
||||
)
|
||||
)
|
||||
if not helper.in_path(
|
||||
helper.get_os_understandable_path(server_info["backup_path"]),
|
||||
if not Helpers.in_path(
|
||||
Helpers.get_os_understandable_path(server_info["backup_path"]),
|
||||
backup_file,
|
||||
) or not os.path.isfile(backup_file):
|
||||
self.redirect("/panel/error?error=Invalid path detected")
|
||||
@ -766,8 +767,9 @@ class PanelHandler(BaseHandler):
|
||||
page_data["user"]["last_ip"] = "N/A"
|
||||
page_data["user"]["last_update"] = "N/A"
|
||||
page_data["user"]["roles"] = set()
|
||||
page_data["user"]["hints"] = True
|
||||
|
||||
if Enum_Permissions_Crafty.User_Config not in exec_user_crafty_permissions:
|
||||
if EnumPermissionsCrafty.USER_CONFIG not in exec_user_crafty_permissions:
|
||||
self.redirect(
|
||||
"/panel/error?error=Unauthorized access: not a user editor"
|
||||
)
|
||||
@ -795,10 +797,10 @@ class PanelHandler(BaseHandler):
|
||||
else:
|
||||
page_data["super-disabled"] = "disabled"
|
||||
for file in sorted(
|
||||
os.listdir(os.path.join(helper.root_dir, "app", "translations"))
|
||||
os.listdir(os.path.join(self.helper.root_dir, "app", "translations"))
|
||||
):
|
||||
if file.endswith(".json"):
|
||||
if file not in helper.get_setting("disabled_language_files"):
|
||||
if file not in self.helper.get_setting("disabled_language_files"):
|
||||
if file != str(page_data["languages"][0] + ".json"):
|
||||
page_data["languages"].append(file.split(".")[0])
|
||||
|
||||
@ -806,7 +808,7 @@ class PanelHandler(BaseHandler):
|
||||
|
||||
elif page == "add_schedule":
|
||||
server_id = self.get_argument("id", None)
|
||||
page_data["schedules"] = management_helper.get_schedules_by_server(
|
||||
page_data["schedules"] = HelpersManagement.get_schedules_by_server(
|
||||
server_id
|
||||
)
|
||||
page_data["get_players"] = lambda: self.controller.stats.get_server_players(
|
||||
@ -814,14 +816,14 @@ class PanelHandler(BaseHandler):
|
||||
)
|
||||
page_data["active_link"] = "schedules"
|
||||
page_data["permissions"] = {
|
||||
"Commands": Enum_Permissions_Server.Commands,
|
||||
"Terminal": Enum_Permissions_Server.Terminal,
|
||||
"Logs": Enum_Permissions_Server.Logs,
|
||||
"Schedule": Enum_Permissions_Server.Schedule,
|
||||
"Backup": Enum_Permissions_Server.Backup,
|
||||
"Files": Enum_Permissions_Server.Files,
|
||||
"Config": Enum_Permissions_Server.Config,
|
||||
"Players": Enum_Permissions_Server.Players,
|
||||
"Commands": EnumPermissionsServer.COMMANDS,
|
||||
"Terminal": EnumPermissionsServer.TERMINAL,
|
||||
"Logs": EnumPermissionsServer.LOGS,
|
||||
"Schedule": EnumPermissionsServer.SCHEDULE,
|
||||
"Backup": EnumPermissionsServer.BACKUP,
|
||||
"Files": EnumPermissionsServer.FILES,
|
||||
"Config": EnumPermissionsServer.CONFIG,
|
||||
"Players": EnumPermissionsServer.PLAYERS,
|
||||
}
|
||||
page_data[
|
||||
"user_permissions"
|
||||
@ -854,7 +856,7 @@ class PanelHandler(BaseHandler):
|
||||
page_data["schedule"]["difficulty"] = "basic"
|
||||
page_data["schedule"]["interval_type"] = "days"
|
||||
|
||||
if not Enum_Permissions_Server.Schedule in page_data["user_permissions"]:
|
||||
if not EnumPermissionsServer.SCHEDULE in page_data["user_permissions"]:
|
||||
if not superuser:
|
||||
self.redirect("/panel/error?error=Unauthorized access To Schedules")
|
||||
return
|
||||
@ -863,7 +865,7 @@ class PanelHandler(BaseHandler):
|
||||
|
||||
elif page == "edit_schedule":
|
||||
server_id = self.get_argument("id", None)
|
||||
page_data["schedules"] = management_helper.get_schedules_by_server(
|
||||
page_data["schedules"] = HelpersManagement.get_schedules_by_server(
|
||||
server_id
|
||||
)
|
||||
sch_id = self.get_argument("sch_id", None)
|
||||
@ -873,14 +875,14 @@ class PanelHandler(BaseHandler):
|
||||
)
|
||||
page_data["active_link"] = "schedules"
|
||||
page_data["permissions"] = {
|
||||
"Commands": Enum_Permissions_Server.Commands,
|
||||
"Terminal": Enum_Permissions_Server.Terminal,
|
||||
"Logs": Enum_Permissions_Server.Logs,
|
||||
"Schedule": Enum_Permissions_Server.Schedule,
|
||||
"Backup": Enum_Permissions_Server.Backup,
|
||||
"Files": Enum_Permissions_Server.Files,
|
||||
"Config": Enum_Permissions_Server.Config,
|
||||
"Players": Enum_Permissions_Server.Players,
|
||||
"Commands": EnumPermissionsServer.COMMANDS,
|
||||
"Terminal": EnumPermissionsServer.TERMINAL,
|
||||
"Logs": EnumPermissionsServer.LOGS,
|
||||
"Schedule": EnumPermissionsServer.SCHEDULE,
|
||||
"Backup": EnumPermissionsServer.BACKUP,
|
||||
"Files": EnumPermissionsServer.FILES,
|
||||
"Config": EnumPermissionsServer.CONFIG,
|
||||
"Players": EnumPermissionsServer.PLAYERS,
|
||||
}
|
||||
page_data[
|
||||
"user_permissions"
|
||||
@ -933,7 +935,7 @@ class PanelHandler(BaseHandler):
|
||||
if sch_id is None or server_id is None:
|
||||
self.redirect("/panel/error?error=Invalid server ID or Schedule ID")
|
||||
|
||||
if not Enum_Permissions_Server.Schedule in page_data["user_permissions"]:
|
||||
if not EnumPermissionsServer.SCHEDULE in page_data["user_permissions"]:
|
||||
if not superuser:
|
||||
self.redirect("/panel/error?error=Unauthorized access To Schedules")
|
||||
return
|
||||
@ -975,19 +977,17 @@ class PanelHandler(BaseHandler):
|
||||
page_data["super-disabled"] = "disabled"
|
||||
|
||||
for file in sorted(
|
||||
os.listdir(os.path.join(helper.root_dir, "app", "translations"))
|
||||
os.listdir(os.path.join(self.helper.root_dir, "app", "translations"))
|
||||
):
|
||||
if file.endswith(".json"):
|
||||
if file not in helper.get_setting("disabled_language_files"):
|
||||
if file not in self.helper.get_setting("disabled_language_files"):
|
||||
if file != str(page_data["languages"][0] + ".json"):
|
||||
page_data["languages"].append(file.split(".")[0])
|
||||
|
||||
if user_id is None:
|
||||
self.redirect("/panel/error?error=Invalid User ID")
|
||||
return
|
||||
elif (
|
||||
Enum_Permissions_Crafty.User_Config not in exec_user_crafty_permissions
|
||||
):
|
||||
elif EnumPermissionsCrafty.USER_CONFIG not in exec_user_crafty_permissions:
|
||||
if str(user_id) != str(exec_user["user_id"]):
|
||||
self.redirect(
|
||||
"/panel/error?error=Unauthorized access: not a user editor"
|
||||
@ -1029,7 +1029,7 @@ class PanelHandler(BaseHandler):
|
||||
|
||||
if (
|
||||
not superuser
|
||||
and Enum_Permissions_Crafty.User_Config
|
||||
and EnumPermissionsCrafty.USER_CONFIG
|
||||
not in exec_user_crafty_permissions
|
||||
):
|
||||
self.redirect("/panel/error?error=Unauthorized access: not superuser")
|
||||
@ -1075,7 +1075,7 @@ class PanelHandler(BaseHandler):
|
||||
page_data["user-roles"] = user_roles
|
||||
page_data["users"] = self.controller.users.get_all_users()
|
||||
|
||||
if Enum_Permissions_Crafty.Roles_Config not in exec_user_crafty_permissions:
|
||||
if EnumPermissionsCrafty.ROLES_CONFIG not in exec_user_crafty_permissions:
|
||||
self.redirect(
|
||||
"/panel/error?error=Unauthorized access: not a role editor"
|
||||
)
|
||||
@ -1103,7 +1103,7 @@ class PanelHandler(BaseHandler):
|
||||
page_data["user-roles"] = user_roles
|
||||
page_data["users"] = self.controller.users.get_all_users()
|
||||
|
||||
if Enum_Permissions_Crafty.Roles_Config not in exec_user_crafty_permissions:
|
||||
if EnumPermissionsCrafty.ROLES_CONFIG not in exec_user_crafty_permissions:
|
||||
self.redirect(
|
||||
"/panel/error?error=Unauthorized access: not a role editor"
|
||||
)
|
||||
@ -1146,7 +1146,7 @@ class PanelHandler(BaseHandler):
|
||||
template = "panel/activity_logs.html"
|
||||
|
||||
elif page == "download_file":
|
||||
file = helper.get_os_understandable_path(self.get_argument("path", ""))
|
||||
file = Helpers.get_os_understandable_path(self.get_argument("path", ""))
|
||||
name = self.get_argument("name", "")
|
||||
|
||||
server_id = self.check_server_id()
|
||||
@ -1155,8 +1155,8 @@ class PanelHandler(BaseHandler):
|
||||
|
||||
server_info = self.controller.servers.get_server_data_by_id(server_id)
|
||||
|
||||
if not helper.in_path(
|
||||
helper.get_os_understandable_path(server_info["path"]), file
|
||||
if not Helpers.in_path(
|
||||
Helpers.get_os_understandable_path(server_info["path"]), file
|
||||
) or not os.path.isfile(file):
|
||||
self.redirect("/panel/error?error=Invalid path detected")
|
||||
return
|
||||
@ -1165,7 +1165,7 @@ class PanelHandler(BaseHandler):
|
||||
self.redirect(f"/panel/server_detail?id={server_id}&subpage=files")
|
||||
|
||||
elif page == "download_support_package":
|
||||
tempZipStorage = exec_user["support_logs"]
|
||||
temp_zip_storage = exec_user["support_logs"]
|
||||
# We'll reset the support path for this user now.
|
||||
self.controller.users.set_support_path(exec_user["user_id"], "")
|
||||
|
||||
@ -1174,8 +1174,8 @@ class PanelHandler(BaseHandler):
|
||||
"Content-Disposition", "attachment; filename=" + "support_logs.zip"
|
||||
)
|
||||
chunk_size = 1024 * 1024 * 4 # 4 MiB
|
||||
if tempZipStorage != "":
|
||||
with open(tempZipStorage, "rb") as f:
|
||||
if temp_zip_storage != "":
|
||||
with open(temp_zip_storage, "rb") as f:
|
||||
while True:
|
||||
chunk = f.read(chunk_size)
|
||||
if not chunk:
|
||||
@ -1230,14 +1230,14 @@ class PanelHandler(BaseHandler):
|
||||
|
||||
server_id = self.get_argument("id", None)
|
||||
permissions = {
|
||||
"Commands": Enum_Permissions_Server.Commands,
|
||||
"Terminal": Enum_Permissions_Server.Terminal,
|
||||
"Logs": Enum_Permissions_Server.Logs,
|
||||
"Schedule": Enum_Permissions_Server.Schedule,
|
||||
"Backup": Enum_Permissions_Server.Backup,
|
||||
"Files": Enum_Permissions_Server.Files,
|
||||
"Config": Enum_Permissions_Server.Config,
|
||||
"Players": Enum_Permissions_Server.Players,
|
||||
"Commands": EnumPermissionsServer.COMMANDS,
|
||||
"Terminal": EnumPermissionsServer.TERMINAL,
|
||||
"Logs": EnumPermissionsServer.LOGS,
|
||||
"Schedule": EnumPermissionsServer.SCHEDULE,
|
||||
"Backup": EnumPermissionsServer.BACKUP,
|
||||
"Files": EnumPermissionsServer.FILES,
|
||||
"Config": EnumPermissionsServer.CONFIG,
|
||||
"Players": EnumPermissionsServer.PLAYERS,
|
||||
}
|
||||
exec_user_role = set()
|
||||
if superuser:
|
||||
@ -1271,13 +1271,13 @@ class PanelHandler(BaseHandler):
|
||||
server_obj = self.controller.servers.get_server_obj(server_id)
|
||||
if superuser:
|
||||
server_path = self.get_argument("server_path", None)
|
||||
if helper.is_os_windows():
|
||||
if Helpers.is_os_windows():
|
||||
server_path.replace(" ", "^ ")
|
||||
server_path = helper.wtol_path(server_path)
|
||||
server_path = Helpers.wtol_path(server_path)
|
||||
log_path = self.get_argument("log_path", None)
|
||||
if helper.is_os_windows():
|
||||
if Helpers.is_os_windows():
|
||||
log_path.replace(" ", "^ ")
|
||||
log_path = helper.wtol_path(log_path)
|
||||
log_path = Helpers.wtol_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)
|
||||
@ -1308,12 +1308,14 @@ class PanelHandler(BaseHandler):
|
||||
|
||||
server_obj.server_name = server_name
|
||||
if superuser:
|
||||
if helper.validate_traversal(
|
||||
helper.get_servers_root_dir(), server_path
|
||||
if Helpers.validate_traversal(
|
||||
self.helper.get_servers_root_dir(), server_path
|
||||
):
|
||||
server_obj.path = server_path
|
||||
server_obj.log_path = log_path
|
||||
if helper.validate_traversal(helper.get_servers_root_dir(), executable):
|
||||
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
|
||||
@ -1358,9 +1360,9 @@ class PanelHandler(BaseHandler):
|
||||
checked = self.controller.management.get_excluded_backup_dirs(server_id)
|
||||
if superuser:
|
||||
backup_path = bleach.clean(self.get_argument("backup_path", None))
|
||||
if helper.is_os_windows():
|
||||
if Helpers.is_os_windows():
|
||||
backup_path.replace(" ", "^ ")
|
||||
backup_path = helper.wtol_path(backup_path)
|
||||
backup_path = Helpers.wtol_path(backup_path)
|
||||
else:
|
||||
backup_path = server_obj.backup_path
|
||||
max_backups = bleach.clean(self.get_argument("max_backups", None))
|
||||
@ -1473,7 +1475,7 @@ class PanelHandler(BaseHandler):
|
||||
one_time = False
|
||||
|
||||
if not superuser and not permissions[
|
||||
"Backup"
|
||||
"Schedule"
|
||||
] in self.controller.server_perms.get_user_id_permissions_list(
|
||||
exec_user["user_id"], server_id
|
||||
):
|
||||
@ -1631,7 +1633,7 @@ class PanelHandler(BaseHandler):
|
||||
one_time = False
|
||||
|
||||
if not superuser and not permissions[
|
||||
"Backup"
|
||||
"Schedule"
|
||||
] in self.controller.server_perms.get_user_id_permissions_list(
|
||||
exec_user["user_id"], server_id
|
||||
):
|
||||
@ -1731,8 +1733,13 @@ class PanelHandler(BaseHandler):
|
||||
password1 = bleach.clean(self.get_argument("password1", None))
|
||||
email = bleach.clean(self.get_argument("email", "default@example.com"))
|
||||
enabled = int(float(self.get_argument("enabled", "0")))
|
||||
try:
|
||||
hints = int(bleach.clean(self.get_argument("hints")))
|
||||
hints = True
|
||||
except:
|
||||
hints = False
|
||||
lang = bleach.clean(
|
||||
self.get_argument("language"), helper.get_setting("language")
|
||||
self.get_argument("language"), self.helper.get_setting("language")
|
||||
)
|
||||
|
||||
if superuser:
|
||||
@ -1749,67 +1756,73 @@ class PanelHandler(BaseHandler):
|
||||
superuser = True
|
||||
else:
|
||||
superuser = False
|
||||
if not exec_user["superuser"]:
|
||||
if (
|
||||
EnumPermissionsCrafty.USER_CONFIG
|
||||
not in exec_user_crafty_permissions
|
||||
):
|
||||
if str(user_id) != str(exec_user["user_id"]):
|
||||
self.redirect(
|
||||
"/panel/error?error=Unauthorized access: not a user editor"
|
||||
)
|
||||
return
|
||||
|
||||
if Enum_Permissions_Crafty.User_Config not in exec_user_crafty_permissions:
|
||||
if str(user_id) != str(exec_user["user_id"]):
|
||||
self.redirect(
|
||||
"/panel/error?error=Unauthorized access: not a user editor"
|
||||
user_data = {
|
||||
"username": username,
|
||||
"password": password0,
|
||||
"email": email,
|
||||
"lang": lang,
|
||||
"hints": hints,
|
||||
}
|
||||
self.controller.users.update_user(user_id, user_data=user_data)
|
||||
|
||||
self.controller.management.add_to_audit_log(
|
||||
exec_user["user_id"],
|
||||
f"Edited user {username} (UID:{user_id}) password",
|
||||
server_id=0,
|
||||
source_ip=self.get_remote_ip(),
|
||||
)
|
||||
self.redirect("/panel/panel_config")
|
||||
return
|
||||
elif username is None or username == "":
|
||||
self.redirect("/panel/error?error=Invalid username")
|
||||
return
|
||||
elif user_id is None:
|
||||
self.redirect("/panel/error?error=Invalid User ID")
|
||||
return
|
||||
else:
|
||||
# does this user id exist?
|
||||
if not self.controller.users.user_id_exists(user_id):
|
||||
self.redirect("/panel/error?error=Invalid User ID")
|
||||
return
|
||||
else:
|
||||
if password0 != password1:
|
||||
self.redirect("/panel/error?error=Passwords must match")
|
||||
return
|
||||
|
||||
roles = self.get_user_role_memberships()
|
||||
permissions_mask, server_quantity = self.get_perms_quantity()
|
||||
|
||||
# if email is None or "":
|
||||
# email = "default@example.com"
|
||||
|
||||
user_data = {
|
||||
"username": username,
|
||||
"password": password0,
|
||||
"email": email,
|
||||
"enabled": enabled,
|
||||
"roles": roles,
|
||||
"lang": lang,
|
||||
"superuser": superuser,
|
||||
"hints": hints,
|
||||
}
|
||||
self.controller.users.update_user(user_id, user_data=user_data)
|
||||
|
||||
self.controller.management.add_to_audit_log(
|
||||
exec_user["user_id"],
|
||||
f"Edited user {username} (UID:{user_id}) password",
|
||||
server_id=0,
|
||||
source_ip=self.get_remote_ip(),
|
||||
user_crafty_data = {
|
||||
"permissions_mask": permissions_mask,
|
||||
"server_quantity": server_quantity,
|
||||
}
|
||||
self.controller.users.update_user(
|
||||
user_id, user_data=user_data, user_crafty_data=user_crafty_data
|
||||
)
|
||||
self.redirect("/panel/panel_config")
|
||||
return
|
||||
elif username is None or username == "":
|
||||
self.redirect("/panel/error?error=Invalid username")
|
||||
return
|
||||
elif user_id is None:
|
||||
self.redirect("/panel/error?error=Invalid User ID")
|
||||
return
|
||||
else:
|
||||
# does this user id exist?
|
||||
if not self.controller.users.user_id_exists(user_id):
|
||||
self.redirect("/panel/error?error=Invalid User ID")
|
||||
return
|
||||
|
||||
if password0 != password1:
|
||||
self.redirect("/panel/error?error=Passwords must match")
|
||||
return
|
||||
|
||||
roles = self.get_user_role_memberships()
|
||||
permissions_mask, server_quantity = self.get_perms_quantity()
|
||||
|
||||
# if email is None or "":
|
||||
# email = "default@example.com"
|
||||
|
||||
user_data = {
|
||||
"username": username,
|
||||
"password": password0,
|
||||
"email": email,
|
||||
"enabled": enabled,
|
||||
"roles": roles,
|
||||
"lang": lang,
|
||||
"superuser": superuser,
|
||||
}
|
||||
user_crafty_data = {
|
||||
"permissions_mask": permissions_mask,
|
||||
"server_quantity": server_quantity,
|
||||
}
|
||||
self.controller.users.update_user(
|
||||
user_id, user_data=user_data, user_crafty_data=user_crafty_data
|
||||
)
|
||||
|
||||
self.controller.management.add_to_audit_log(
|
||||
exec_user["user_id"],
|
||||
@ -1844,8 +1857,8 @@ class PanelHandler(BaseHandler):
|
||||
name,
|
||||
user_id,
|
||||
superuser,
|
||||
crafty_permissions_mask,
|
||||
server_permissions_mask,
|
||||
crafty_permissions_mask,
|
||||
)
|
||||
|
||||
self.controller.management.add_to_audit_log(
|
||||
@ -1874,13 +1887,15 @@ class PanelHandler(BaseHandler):
|
||||
self.controller.management.add_to_audit_log(
|
||||
exec_user["user_id"],
|
||||
f"Generated a new API token for the key {key.name} "
|
||||
f"from user with UID: {key.user.user_id}",
|
||||
f"from user with UID: {key.user_id}",
|
||||
server_id=0,
|
||||
source_ip=self.get_remote_ip(),
|
||||
)
|
||||
|
||||
self.write(
|
||||
authentication.generate(key.user.user_id, {"token_id": key.token_id})
|
||||
self.controller.authentication.generate(
|
||||
key.user_id.user_id, {"token_id": key.token_id}
|
||||
)
|
||||
)
|
||||
self.finish()
|
||||
|
||||
@ -1897,19 +1912,21 @@ class PanelHandler(BaseHandler):
|
||||
password1 = bleach.clean(self.get_argument("password1", None))
|
||||
email = bleach.clean(self.get_argument("email", "default@example.com"))
|
||||
enabled = int(float(self.get_argument("enabled", "0")))
|
||||
hints = True
|
||||
lang = bleach.clean(
|
||||
self.get_argument("lang", helper.get_setting("language"))
|
||||
self.get_argument("lang", self.helper.get_setting("language"))
|
||||
)
|
||||
# We don't want a non-super user to be able to create a super user.
|
||||
if superuser:
|
||||
superuser = bleach.clean(self.get_argument("superuser", "0"))
|
||||
new_superuser = bleach.clean(self.get_argument("superuser", "0"))
|
||||
else:
|
||||
superuser = "0"
|
||||
new_superuser = "0"
|
||||
if superuser == "1":
|
||||
superuser = True
|
||||
new_superuser = True
|
||||
else:
|
||||
superuser = False
|
||||
new_superuser = False
|
||||
|
||||
if Enum_Permissions_Crafty.User_Config not in exec_user_crafty_permissions:
|
||||
if EnumPermissionsCrafty.USER_CONFIG not in exec_user_crafty_permissions:
|
||||
self.redirect(
|
||||
"/panel/error?error=Unauthorized access: not a user editor"
|
||||
)
|
||||
@ -1935,12 +1952,9 @@ class PanelHandler(BaseHandler):
|
||||
password=password0,
|
||||
email=email,
|
||||
enabled=enabled,
|
||||
superuser=superuser,
|
||||
superuser=new_superuser,
|
||||
)
|
||||
user_data = {
|
||||
"roles": roles,
|
||||
"lang": lang,
|
||||
}
|
||||
user_data = {"roles": roles, "lang": lang, "hints": True}
|
||||
user_crafty_data = {
|
||||
"permissions_mask": permissions_mask,
|
||||
"server_quantity": server_quantity,
|
||||
@ -1967,7 +1981,7 @@ class PanelHandler(BaseHandler):
|
||||
role_id = bleach.clean(self.get_argument("id", None))
|
||||
role_name = bleach.clean(self.get_argument("role_name", None))
|
||||
|
||||
if Enum_Permissions_Crafty.Roles_Config not in exec_user_crafty_permissions:
|
||||
if EnumPermissionsCrafty.ROLES_CONFIG not in exec_user_crafty_permissions:
|
||||
self.redirect(
|
||||
"/panel/error?error=Unauthorized access: not a role editor"
|
||||
)
|
||||
@ -2003,7 +2017,7 @@ class PanelHandler(BaseHandler):
|
||||
elif page == "add_role":
|
||||
role_name = bleach.clean(self.get_argument("role_name", None))
|
||||
|
||||
if Enum_Permissions_Crafty.Roles_Config not in exec_user_crafty_permissions:
|
||||
if EnumPermissionsCrafty.ROLES_CONFIG not in exec_user_crafty_permissions:
|
||||
self.redirect(
|
||||
"/panel/error?error=Unauthorized access: not a role editor"
|
||||
)
|
||||
@ -2042,8 +2056,8 @@ class PanelHandler(BaseHandler):
|
||||
else:
|
||||
self.set_status(404)
|
||||
page_data = {
|
||||
"lang": helper.get_setting("language"),
|
||||
"lang_page": helper.getLangPage(helper.get_setting("language")),
|
||||
"lang": self.helper.get_setting("language"),
|
||||
"lang_page": Helpers.get_lang_page(self.helper.get_setting("language")),
|
||||
}
|
||||
self.render(
|
||||
"public/404.html", translate=self.translator.translate, data=page_data
|
||||
@ -2059,12 +2073,12 @@ class PanelHandler(BaseHandler):
|
||||
page_data = {
|
||||
# todo: make this actually pull and compare version data
|
||||
"update_available": False,
|
||||
"version_data": helper.get_version_string(),
|
||||
"version_data": self.helper.get_version_string(),
|
||||
"user_data": exec_user,
|
||||
"hosts_data": self.controller.management.get_latest_hosts_stats(),
|
||||
"show_contribute": helper.get_setting("show_contribute_link", True),
|
||||
"show_contribute": self.helper.get_setting("show_contribute_link", True),
|
||||
"lang": self.controller.users.get_user_lang_by_id(exec_user["user_id"]),
|
||||
"lang_page": helper.getLangPage(
|
||||
"lang_page": Helpers.get_lang_page(
|
||||
self.controller.users.get_user_lang_by_id(exec_user["user_id"])
|
||||
),
|
||||
}
|
||||
|
@ -1,24 +1,17 @@
|
||||
import logging
|
||||
import bleach
|
||||
|
||||
from app.classes.models.users import Users
|
||||
from app.classes.shared.authentication import authentication
|
||||
from app.classes.shared.helpers import helper
|
||||
from app.classes.shared.main_models import fn
|
||||
from app.classes.shared.helpers import Helpers
|
||||
from app.classes.models.users import HelperUsers
|
||||
from app.classes.web.base_handler import BaseHandler
|
||||
|
||||
try:
|
||||
import bleach
|
||||
|
||||
except ModuleNotFoundError as e:
|
||||
helper.auto_installer_fix(e)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class PublicHandler(BaseHandler):
|
||||
def set_current_user(self, user_id: str = None):
|
||||
|
||||
expire_days = helper.get_setting("cookie_expire")
|
||||
expire_days = self.helper.get_setting("cookie_expire")
|
||||
|
||||
# if helper comes back with false
|
||||
if not expire_days:
|
||||
@ -26,7 +19,9 @@ class PublicHandler(BaseHandler):
|
||||
|
||||
if user_id is not None:
|
||||
self.set_cookie(
|
||||
"token", authentication.generate(user_id), expires_days=int(expire_days)
|
||||
"token",
|
||||
self.controller.authentication.generate(user_id),
|
||||
expires_days=int(expire_days),
|
||||
)
|
||||
else:
|
||||
self.clear_cookie("token")
|
||||
@ -37,14 +32,18 @@ class PublicHandler(BaseHandler):
|
||||
|
||||
error = bleach.clean(self.get_argument("error", "Invalid Login!"))
|
||||
error_msg = bleach.clean(self.get_argument("error_msg", ""))
|
||||
|
||||
page_data = {
|
||||
"version": helper.get_version_string(),
|
||||
"error": error,
|
||||
"lang": helper.get_setting("language"),
|
||||
"lang_page": helper.getLangPage(helper.get_setting("language")),
|
||||
"query": "",
|
||||
}
|
||||
try:
|
||||
page_data = {
|
||||
"version": self.helper.get_version_string(),
|
||||
"error": error,
|
||||
"lang": self.helper.get_setting("language"),
|
||||
"lang_page": self.helper.get_lang_page(
|
||||
self.helper.get_setting("language")
|
||||
),
|
||||
"query": "",
|
||||
}
|
||||
except:
|
||||
self.redirect("/public/login.html")
|
||||
if self.request.query:
|
||||
page_data["query"] = self.request.query
|
||||
|
||||
@ -88,10 +87,10 @@ class PublicHandler(BaseHandler):
|
||||
error_msg = bleach.clean(self.get_argument("error_msg", ""))
|
||||
|
||||
page_data = {
|
||||
"version": helper.get_version_string(),
|
||||
"version": self.helper.get_version_string(),
|
||||
"error": error,
|
||||
"lang": helper.get_setting("language"),
|
||||
"lang_page": helper.getLangPage(helper.get_setting("language")),
|
||||
"lang": self.helper.get_setting("language"),
|
||||
"lang_page": self.helper.get_lang_page(self.helper.get_setting("language")),
|
||||
"query": "",
|
||||
}
|
||||
if self.request.query:
|
||||
@ -107,9 +106,21 @@ class PublicHandler(BaseHandler):
|
||||
entered_password = bleach.clean(self.get_argument("password"))
|
||||
|
||||
# pylint: disable=no-member
|
||||
user_data = Users.get_or_none(
|
||||
fn.Lower(Users.username) == entered_username.lower()
|
||||
)
|
||||
try:
|
||||
user_id = HelperUsers.get_user_id_by_name(entered_username.lower())
|
||||
user_data = HelperUsers.get_user_model(user_id)
|
||||
except:
|
||||
error_msg = "Incorrect username or password. Please try again."
|
||||
# self.clear_cookie("user")
|
||||
# self.clear_cookie("user_data")
|
||||
self.clear_cookie("token")
|
||||
if self.request.query:
|
||||
self.redirect(
|
||||
f"/public/login?error_msg={error_msg}&{self.request.query}"
|
||||
)
|
||||
else:
|
||||
self.redirect(f"/public/login?error_msg={error_msg}")
|
||||
return
|
||||
|
||||
# if we don't have a user
|
||||
if not user_data:
|
||||
@ -142,7 +153,7 @@ class PublicHandler(BaseHandler):
|
||||
self.redirect(f"/public/login?error_msg={error_msg}")
|
||||
return
|
||||
|
||||
login_result = helper.verify_pass(entered_password, user_data.password)
|
||||
login_result = self.helper.verify_pass(entered_password, user_data.password)
|
||||
|
||||
# Valid Login
|
||||
if login_result:
|
||||
@ -152,14 +163,9 @@ class PublicHandler(BaseHandler):
|
||||
)
|
||||
|
||||
# record this login
|
||||
q = (
|
||||
Users.select()
|
||||
.where(Users.username == entered_username.lower())
|
||||
.get()
|
||||
)
|
||||
q.last_ip = self.get_remote_ip()
|
||||
q.last_login = helper.get_time_as_string()
|
||||
q.save()
|
||||
user_data.last_ip = self.get_remote_ip()
|
||||
user_data.last_login = Helpers.get_time_as_string()
|
||||
user_data.save()
|
||||
|
||||
# log this login
|
||||
self.controller.management.add_to_audit_log(
|
||||
|
@ -1,31 +1,28 @@
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import tornado.web
|
||||
import tornado.escape
|
||||
import bleach
|
||||
import libgravatar
|
||||
import requests
|
||||
|
||||
from app.classes.minecraft.serverjars import server_jar_obj
|
||||
from app.classes.models.crafty_permissions import Enum_Permissions_Crafty
|
||||
from app.classes.shared.helpers import helper
|
||||
from app.classes.shared.file_helpers import file_helper
|
||||
from app.classes.models.crafty_permissions import EnumPermissionsCrafty
|
||||
from app.classes.shared.helpers import Helpers
|
||||
from app.classes.shared.file_helpers import FileHelpers
|
||||
from app.classes.web.base_handler import BaseHandler
|
||||
|
||||
try:
|
||||
import tornado.web
|
||||
import tornado.escape
|
||||
import bleach
|
||||
import libgravatar
|
||||
import requests
|
||||
|
||||
except ModuleNotFoundError as e:
|
||||
helper.auto_installer_fix(e)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ServerHandler(BaseHandler):
|
||||
@tornado.web.authenticated
|
||||
def get(self, page):
|
||||
# pylint: disable=unused-variable
|
||||
api_key, token_data, exec_user = self.current_user
|
||||
(
|
||||
api_key,
|
||||
_token_data,
|
||||
exec_user,
|
||||
) = self.current_user
|
||||
superuser = exec_user["superuser"]
|
||||
if api_key is not None:
|
||||
superuser = superuser and api_key.superuser
|
||||
@ -58,15 +55,15 @@ class ServerHandler(BaseHandler):
|
||||
template = "public/404.html"
|
||||
|
||||
page_data = {
|
||||
"version_data": helper.get_version_string(),
|
||||
"version_data": self.helper.get_version_string(),
|
||||
"user_data": exec_user,
|
||||
"user_role": exec_user_role,
|
||||
"roles": list_roles,
|
||||
"user_crafty_permissions": exec_user_crafty_permissions,
|
||||
"crafty_permissions": {
|
||||
"Server_Creation": Enum_Permissions_Crafty.Server_Creation,
|
||||
"User_Config": Enum_Permissions_Crafty.User_Config,
|
||||
"Roles_Config": Enum_Permissions_Crafty.Roles_Config,
|
||||
"Server_Creation": EnumPermissionsCrafty.SERVER_CREATION,
|
||||
"User_Config": EnumPermissionsCrafty.USER_CONFIG,
|
||||
"Roles_Config": EnumPermissionsCrafty.ROLES_CONFIG,
|
||||
},
|
||||
"server_stats": {
|
||||
"total": len(self.controller.list_defined_servers()),
|
||||
@ -78,9 +75,9 @@ class ServerHandler(BaseHandler):
|
||||
},
|
||||
"hosts_data": self.controller.management.get_latest_hosts_stats(),
|
||||
"menu_servers": defined_servers,
|
||||
"show_contribute": helper.get_setting("show_contribute_link", True),
|
||||
"show_contribute": self.helper.get_setting("show_contribute_link", True),
|
||||
"lang": self.controller.users.get_user_lang_by_id(exec_user["user_id"]),
|
||||
"lang_page": helper.getLangPage(
|
||||
"lang_page": Helpers.get_lang_page(
|
||||
self.controller.users.get_user_lang_by_id(exec_user["user_id"])
|
||||
),
|
||||
"api_key": {
|
||||
@ -95,14 +92,16 @@ class ServerHandler(BaseHandler):
|
||||
"superuser": superuser,
|
||||
}
|
||||
|
||||
if helper.get_setting("allow_nsfw_profile_pictures"):
|
||||
if self.helper.get_setting("allow_nsfw_profile_pictures"):
|
||||
rating = "x"
|
||||
else:
|
||||
rating = "g"
|
||||
|
||||
if exec_user["email"] != "default@example.com" or "":
|
||||
g = libgravatar.Gravatar(libgravatar.sanitize_email(exec_user["email"]))
|
||||
url = g.get_image(
|
||||
gravatar = libgravatar.Gravatar(
|
||||
libgravatar.sanitize_email(exec_user["email"])
|
||||
)
|
||||
url = gravatar.get_image(
|
||||
size=80,
|
||||
default="404",
|
||||
force_default=False,
|
||||
@ -110,9 +109,12 @@ class ServerHandler(BaseHandler):
|
||||
filetype_extension=False,
|
||||
use_ssl=True,
|
||||
) # + "?d=404"
|
||||
if requests.head(url).status_code != 404:
|
||||
profile_url = url
|
||||
else:
|
||||
try:
|
||||
if requests.head(url).status_code != 404:
|
||||
profile_url = url
|
||||
else:
|
||||
profile_url = "/static/assets/images/faces-clipart/pic-3.png"
|
||||
except:
|
||||
profile_url = "/static/assets/images/faces-clipart/pic-3.png"
|
||||
else:
|
||||
profile_url = "/static/assets/images/faces-clipart/pic-3.png"
|
||||
@ -131,9 +133,10 @@ class ServerHandler(BaseHandler):
|
||||
)
|
||||
return
|
||||
|
||||
page_data["server_types"] = server_jar_obj.get_serverjar_data()
|
||||
page_data["online"] = Helpers.check_internet()
|
||||
page_data["server_types"] = self.controller.server_jars.get_serverjar_data()
|
||||
page_data["js_server_types"] = json.dumps(
|
||||
server_jar_obj.get_serverjar_data()
|
||||
self.controller.server_jars.get_serverjar_data()
|
||||
)
|
||||
template = "server/wizard.html"
|
||||
|
||||
@ -157,8 +160,7 @@ class ServerHandler(BaseHandler):
|
||||
|
||||
@tornado.web.authenticated
|
||||
def post(self, page):
|
||||
# pylint: disable=unused-variable
|
||||
api_key, token_data, exec_user = self.current_user
|
||||
api_key, _token_data, exec_user = self.current_user
|
||||
superuser = exec_user["superuser"]
|
||||
if api_key is not None:
|
||||
superuser = superuser and api_key.superuser
|
||||
@ -167,9 +169,9 @@ class ServerHandler(BaseHandler):
|
||||
page_data = {
|
||||
"version_data": "version_data_here", # TODO
|
||||
"user_data": exec_user,
|
||||
"show_contribute": helper.get_setting("show_contribute_link", True),
|
||||
"show_contribute": self.helper.get_setting("show_contribute_link", True),
|
||||
"lang": self.controller.users.get_user_lang_by_id(exec_user["user_id"]),
|
||||
"lang_page": helper.getLangPage(
|
||||
"lang_page": Helpers.get_lang_page(
|
||||
self.controller.users.get_user_lang_by_id(exec_user["user_id"])
|
||||
),
|
||||
}
|
||||
@ -200,15 +202,17 @@ class ServerHandler(BaseHandler):
|
||||
server_data.get("server_name") + f" (Copy {name_counter})"
|
||||
)
|
||||
|
||||
new_server_uuid = helper.create_uuid()
|
||||
new_server_uuid = Helpers.create_uuid()
|
||||
while os.path.exists(
|
||||
os.path.join(helper.servers_dir, new_server_uuid)
|
||||
os.path.join(self.helper.servers_dir, new_server_uuid)
|
||||
):
|
||||
new_server_uuid = helper.create_uuid()
|
||||
new_server_path = os.path.join(helper.servers_dir, new_server_uuid)
|
||||
new_server_uuid = Helpers.create_uuid()
|
||||
new_server_path = os.path.join(
|
||||
self.helper.servers_dir, new_server_uuid
|
||||
)
|
||||
|
||||
# copy the old server
|
||||
file_helper.copy_dir(server_data.get("path"), new_server_path)
|
||||
FileHelpers.copy_dir(server_data.get("path"), new_server_path)
|
||||
|
||||
# TODO get old server DB data to individual variables
|
||||
stop_command = server_data.get("stop_command")
|
||||
@ -217,8 +221,9 @@ class ServerHandler(BaseHandler):
|
||||
).replace(server_uuid, new_server_uuid)
|
||||
new_executable = server_data.get("executable")
|
||||
new_server_log_file = str(
|
||||
helper.get_os_understandable_path(server_data.get("log_path"))
|
||||
Helpers.get_os_understandable_path(server_data.get("log_path"))
|
||||
).replace(server_uuid, new_server_uuid)
|
||||
backup_path = os.path.join(self.helper.backup_path, new_server_uuid)
|
||||
server_port = server_data.get("server_port")
|
||||
server_type = server_data.get("type")
|
||||
|
||||
@ -226,7 +231,7 @@ class ServerHandler(BaseHandler):
|
||||
new_server_name,
|
||||
new_server_uuid,
|
||||
new_server_path,
|
||||
"",
|
||||
backup_path,
|
||||
new_server_command,
|
||||
new_executable,
|
||||
new_server_log_file,
|
||||
@ -295,7 +300,7 @@ class ServerHandler(BaseHandler):
|
||||
elif import_type == "import_zip":
|
||||
# here import_server_path means the zip path
|
||||
zip_path = bleach.clean(self.get_argument("root_path"))
|
||||
good_path = helper.check_path_exists(zip_path)
|
||||
good_path = Helpers.check_path_exists(zip_path)
|
||||
if not good_path:
|
||||
self.redirect("/panel/error?error=Temp path not found!")
|
||||
return
|
||||
@ -318,7 +323,7 @@ class ServerHandler(BaseHandler):
|
||||
self.get_remote_ip(),
|
||||
)
|
||||
# deletes temp dir
|
||||
file_helper.del_dirs(zip_path)
|
||||
FileHelpers.del_dirs(zip_path)
|
||||
else:
|
||||
if len(server_parts) != 2:
|
||||
self.redirect("/panel/error?error=Invalid server data")
|
||||
@ -326,7 +331,6 @@ class ServerHandler(BaseHandler):
|
||||
server_type, server_version = server_parts
|
||||
# TODO: add server type check here and call the correct server
|
||||
# add functions if not a jar
|
||||
role_ids = self.controller.users.get_user_roles_id(exec_user["user_id"])
|
||||
new_server_id = self.controller.create_jar_server(
|
||||
server_type, server_version, server_name, min_mem, max_mem, port
|
||||
)
|
||||
@ -413,7 +417,7 @@ class ServerHandler(BaseHandler):
|
||||
elif import_type == "import_zip":
|
||||
# here import_server_path means the zip path
|
||||
zip_path = bleach.clean(self.get_argument("root_path"))
|
||||
good_path = helper.check_path_exists(zip_path)
|
||||
good_path = Helpers.check_path_exists(zip_path)
|
||||
if not good_path:
|
||||
self.redirect("/panel/error?error=Temp path not found!")
|
||||
return
|
||||
@ -436,7 +440,7 @@ class ServerHandler(BaseHandler):
|
||||
self.get_remote_ip(),
|
||||
)
|
||||
# deletes temp dir
|
||||
file_helper.del_dirs(zip_path)
|
||||
FileHelpers.del_dirs(zip_path)
|
||||
else:
|
||||
if len(server_parts) != 2:
|
||||
self.redirect("/panel/error?error=Invalid server data")
|
||||
@ -444,7 +448,6 @@ class ServerHandler(BaseHandler):
|
||||
server_type, server_version = server_parts
|
||||
# TODO: add server type check here and call the correct server
|
||||
# add functions if not a jar
|
||||
role_ids = self.controller.users.get_user_roles_id(exec_user["user_id"])
|
||||
new_server_id = self.controller.create_jar_server(
|
||||
server_type, server_version, server_name, min_mem, max_mem, port
|
||||
)
|
||||
|
@ -1,6 +1,5 @@
|
||||
import logging
|
||||
|
||||
from app.classes.shared.helpers import helper
|
||||
from app.classes.web.base_handler import BaseHandler
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@ -9,8 +8,10 @@ logger = logging.getLogger(__name__)
|
||||
class StatusHandler(BaseHandler):
|
||||
def get(self):
|
||||
page_data = {}
|
||||
page_data["lang"] = helper.get_setting("language")
|
||||
page_data["lang_page"] = helper.getLangPage(helper.get_setting("language"))
|
||||
page_data["lang"] = self.helper.get_setting("language")
|
||||
page_data["lang_page"] = self.helper.get_lang_page(
|
||||
self.helper.get_setting("language")
|
||||
)
|
||||
page_data["servers"] = self.controller.servers.get_all_servers_stats()
|
||||
running = 0
|
||||
for srv in page_data["servers"]:
|
||||
|
@ -3,43 +3,50 @@ import sys
|
||||
import json
|
||||
import asyncio
|
||||
import logging
|
||||
import tornado.web
|
||||
import tornado.ioloop
|
||||
import tornado.log
|
||||
import tornado.template
|
||||
import tornado.escape
|
||||
import tornado.locale
|
||||
import tornado.httpserver
|
||||
|
||||
from app.classes.shared.translation import translation
|
||||
from app.classes.shared.console import console
|
||||
from app.classes.shared.helpers import helper
|
||||
from app.classes.shared.console import Console
|
||||
from app.classes.shared.helpers import Helpers
|
||||
from app.classes.web.file_handler import FileHandler
|
||||
from app.classes.web.public_handler import PublicHandler
|
||||
from app.classes.web.panel_handler import PanelHandler
|
||||
from app.classes.web.default_handler import DefaultHandler
|
||||
from app.classes.web.server_handler import ServerHandler
|
||||
from app.classes.web.ajax_handler import AjaxHandler
|
||||
from app.classes.web.api_handler import ServersStats, NodeStats
|
||||
from app.classes.web.api_handler import (
|
||||
ServersStats,
|
||||
NodeStats,
|
||||
ServerBackup,
|
||||
StartServer,
|
||||
StopServer,
|
||||
RestartServer,
|
||||
CreateUser,
|
||||
DeleteUser,
|
||||
ListServers,
|
||||
SendCommand,
|
||||
)
|
||||
from app.classes.web.websocket_handler import SocketHandler
|
||||
from app.classes.web.static_handler import CustomStaticHandler
|
||||
from app.classes.web.upload_handler import UploadHandler
|
||||
from app.classes.web.http_handler import HTTPHandler, HTTPHandlerPage
|
||||
from app.classes.web.status_handler import StatusHandler
|
||||
|
||||
try:
|
||||
import tornado.web
|
||||
import tornado.ioloop
|
||||
import tornado.log
|
||||
import tornado.template
|
||||
import tornado.escape
|
||||
import tornado.locale
|
||||
import tornado.httpserver
|
||||
|
||||
except ModuleNotFoundError as e:
|
||||
helper.auto_installer_fix(e)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Webserver:
|
||||
def __init__(self, controller, tasks_manager):
|
||||
def __init__(self, helper, controller, tasks_manager):
|
||||
self.ioloop = None
|
||||
self.HTTP_Server = None
|
||||
self.HTTPS_Server = None
|
||||
self.http_server = None
|
||||
self.https_server = None
|
||||
self.helper = helper
|
||||
self.controller = controller
|
||||
self.tasks_manager = tasks_manager
|
||||
self._asyncio_patch()
|
||||
@ -92,16 +99,16 @@ class Webserver:
|
||||
def run_tornado(self):
|
||||
|
||||
# let's verify we have an SSL cert
|
||||
helper.create_self_signed_cert()
|
||||
self.helper.create_self_signed_cert()
|
||||
|
||||
http_port = helper.get_setting("http_port")
|
||||
https_port = helper.get_setting("https_port")
|
||||
http_port = self.helper.get_setting("http_port")
|
||||
https_port = self.helper.get_setting("https_port")
|
||||
|
||||
debug_errors = helper.get_setting("show_errors")
|
||||
cookie_secret = helper.get_setting("cookie_secret")
|
||||
debug_errors = self.helper.get_setting("show_errors")
|
||||
cookie_secret = self.helper.get_setting("cookie_secret")
|
||||
|
||||
if cookie_secret is False:
|
||||
cookie_secret = helper.random_string_generator(32)
|
||||
cookie_secret = self.helper.random_string_generator(32)
|
||||
|
||||
if not http_port:
|
||||
http_port = 8000
|
||||
@ -111,10 +118,10 @@ class Webserver:
|
||||
|
||||
cert_objects = {
|
||||
"certfile": os.path.join(
|
||||
helper.config_dir, "web", "certs", "commander.cert.pem"
|
||||
self.helper.config_dir, "web", "certs", "commander.cert.pem"
|
||||
),
|
||||
"keyfile": os.path.join(
|
||||
helper.config_dir, "web", "certs", "commander.key.pem"
|
||||
self.helper.config_dir, "web", "certs", "commander.key.pem"
|
||||
),
|
||||
}
|
||||
|
||||
@ -128,9 +135,10 @@ class Webserver:
|
||||
tornado.locale.set_default_locale("en_EN")
|
||||
|
||||
handler_args = {
|
||||
"helper": self.helper,
|
||||
"controller": self.controller,
|
||||
"tasks_manager": self.tasks_manager,
|
||||
"translator": translation,
|
||||
"translator": self.helper.translation,
|
||||
}
|
||||
handlers = [
|
||||
(r"/", DefaultHandler, handler_args),
|
||||
@ -139,17 +147,26 @@ class Webserver:
|
||||
(r"/server/(.*)", ServerHandler, handler_args),
|
||||
(r"/ajax/(.*)", AjaxHandler, handler_args),
|
||||
(r"/files/(.*)", FileHandler, handler_args),
|
||||
(r"/api/stats/servers", ServersStats, handler_args),
|
||||
(r"/api/stats/node", NodeStats, handler_args),
|
||||
(r"/ws", SocketHandler, handler_args),
|
||||
(r"/upload", UploadHandler, handler_args),
|
||||
(r"/status", StatusHandler, handler_args),
|
||||
# API Routes
|
||||
(r"/api/v1/stats/servers", ServersStats, handler_args),
|
||||
(r"/api/v1/stats/node", NodeStats, handler_args),
|
||||
(r"/api/v1/server/send_command", SendCommand, handler_args),
|
||||
(r"/api/v1/server/backup", ServerBackup, handler_args),
|
||||
(r"/api/v1/server/start", StartServer, handler_args),
|
||||
(r"/api/v1/server/stop", StopServer, handler_args),
|
||||
(r"/api/v1/server/restart", RestartServer, handler_args),
|
||||
(r"/api/v1/list_servers", ListServers, handler_args),
|
||||
(r"/api/v1/users/create_user", CreateUser, handler_args),
|
||||
(r"/api/v1/users/delete_user", DeleteUser, handler_args),
|
||||
]
|
||||
|
||||
app = tornado.web.Application(
|
||||
handlers,
|
||||
template_path=os.path.join(helper.webroot, "templates"),
|
||||
static_path=os.path.join(helper.webroot, "static"),
|
||||
template_path=os.path.join(self.helper.webroot, "templates"),
|
||||
static_path=os.path.join(self.helper.webroot, "static"),
|
||||
debug=debug_errors,
|
||||
cookie_secret=cookie_secret,
|
||||
xsrf_cookies=True,
|
||||
@ -160,7 +177,7 @@ class Webserver:
|
||||
static_handler_class=CustomStaticHandler,
|
||||
serve_traceback=debug_errors,
|
||||
)
|
||||
HTTPhanders = [
|
||||
http_handers = [
|
||||
(r"/", HTTPHandler, handler_args),
|
||||
(r"/public/(.*)", HTTPHandlerPage, handler_args),
|
||||
(r"/panel/(.*)", HTTPHandlerPage, handler_args),
|
||||
@ -171,10 +188,10 @@ class Webserver:
|
||||
(r"/ws", HTTPHandlerPage, handler_args),
|
||||
(r"/upload", HTTPHandlerPage, handler_args),
|
||||
]
|
||||
HTTPapp = tornado.web.Application(
|
||||
HTTPhanders,
|
||||
template_path=os.path.join(helper.webroot, "templates"),
|
||||
static_path=os.path.join(helper.webroot, "static"),
|
||||
http_app = tornado.web.Application(
|
||||
http_handers,
|
||||
template_path=os.path.join(self.helper.webroot, "templates"),
|
||||
static_path=os.path.join(self.helper.webroot, "static"),
|
||||
debug=debug_errors,
|
||||
cookie_secret=cookie_secret,
|
||||
xsrf_cookies=True,
|
||||
@ -185,31 +202,31 @@ class Webserver:
|
||||
serve_traceback=debug_errors,
|
||||
)
|
||||
|
||||
self.HTTP_Server = tornado.httpserver.HTTPServer(HTTPapp)
|
||||
self.HTTP_Server.listen(http_port)
|
||||
self.http_server = tornado.httpserver.HTTPServer(http_app)
|
||||
self.http_server.listen(http_port)
|
||||
|
||||
self.HTTPS_Server = tornado.httpserver.HTTPServer(app, ssl_options=cert_objects)
|
||||
self.HTTPS_Server.listen(https_port)
|
||||
self.https_server = tornado.httpserver.HTTPServer(app, ssl_options=cert_objects)
|
||||
self.https_server.listen(https_port)
|
||||
|
||||
logger.info(
|
||||
f"https://{helper.get_local_ip()}:{https_port} "
|
||||
f"https://{Helpers.get_local_ip()}:{https_port} "
|
||||
f"is up and ready for connections."
|
||||
)
|
||||
console.info(
|
||||
f"https://{helper.get_local_ip()}:{https_port} "
|
||||
Console.info(
|
||||
f"https://{Helpers.get_local_ip()}:{https_port} "
|
||||
f"is up and ready for connections."
|
||||
)
|
||||
|
||||
console.info("Server Init Complete: Listening For Connections:")
|
||||
Console.info("Server Init Complete: Listening For Connections:")
|
||||
|
||||
self.ioloop = tornado.ioloop.IOLoop.current()
|
||||
self.ioloop.start()
|
||||
|
||||
def stop_web_server(self):
|
||||
logger.info("Shutting Down Web Server")
|
||||
console.info("Shutting Down Web Server")
|
||||
Console.info("Shutting Down Web Server")
|
||||
self.ioloop.stop()
|
||||
self.HTTP_Server.stop()
|
||||
self.HTTPS_Server.stop()
|
||||
self.http_server.stop()
|
||||
self.https_server.stop()
|
||||
logger.info("Web Server Stopped")
|
||||
console.info("Web Server Stopped")
|
||||
Console.info("Web Server Stopped")
|
||||
|
@ -1,48 +1,66 @@
|
||||
import logging
|
||||
import os
|
||||
import time
|
||||
import tornado.web
|
||||
import tornado.options
|
||||
import tornado.httpserver
|
||||
|
||||
from app.classes.models.server_permissions import Enum_Permissions_Server
|
||||
from app.classes.shared.helpers import helper
|
||||
from app.classes.shared.console import console
|
||||
from app.classes.models.server_permissions import EnumPermissionsServer
|
||||
from app.classes.shared.console import Console
|
||||
from app.classes.shared.helpers import Helpers
|
||||
from app.classes.shared.main_controller import Controller
|
||||
from app.classes.web.websocket_helper import websocket_helper
|
||||
from app.classes.web.base_handler import BaseHandler
|
||||
|
||||
try:
|
||||
import tornado.web
|
||||
import tornado.options
|
||||
import tornado.httpserver
|
||||
|
||||
except ModuleNotFoundError as ex:
|
||||
helper.auto_installer_fix(ex)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Class & Function Defination
|
||||
MAX_STREAMED_SIZE = 1024 * 1024 * 1024
|
||||
|
||||
|
||||
@tornado.web.stream_request_body
|
||||
class UploadHandler(BaseHandler):
|
||||
|
||||
# noinspection PyAttributeOutsideInit
|
||||
def initialize(
|
||||
self, controller: Controller = None, tasks_manager=None, translator=None
|
||||
self,
|
||||
helper: Helpers = None,
|
||||
controller: Controller = None,
|
||||
tasks_manager=None,
|
||||
translator=None,
|
||||
):
|
||||
self.helper = helper
|
||||
self.controller = controller
|
||||
self.tasks_manager = tasks_manager
|
||||
self.translator = translator
|
||||
|
||||
def prepare(self):
|
||||
self.do_upload = True
|
||||
# pylint: disable=unused-variable
|
||||
api_key, token_data, exec_user = self.current_user
|
||||
# Class & Function Defination
|
||||
api_key, _token_data, exec_user = self.current_user
|
||||
server_id = self.get_argument("server_id", None)
|
||||
superuser = exec_user["superuser"]
|
||||
if api_key is not None:
|
||||
superuser = superuser and api_key.superuser
|
||||
user_id = exec_user["user_id"]
|
||||
stream_size_value = self.helper.get_setting("stream_size_GB")
|
||||
|
||||
max_streamed_size = (1024 * 1024 * 1024) * stream_size_value
|
||||
|
||||
self.content_len = int(self.request.headers.get("Content-Length"))
|
||||
if self.content_len > max_streamed_size:
|
||||
logger.error(
|
||||
f"User with ID {user_id} attempted to upload a file that"
|
||||
f" exceeded the max body size."
|
||||
)
|
||||
self.helper.websocket_helper.broadcast_user(
|
||||
user_id,
|
||||
"send_start_error",
|
||||
{
|
||||
"error": self.helper.translation.translate(
|
||||
"error",
|
||||
"fileTooLarge",
|
||||
self.controller.users.get_user_lang_by_id(user_id),
|
||||
),
|
||||
},
|
||||
)
|
||||
return
|
||||
self.do_upload = True
|
||||
|
||||
if superuser:
|
||||
exec_user_server_permissions = (
|
||||
@ -65,20 +83,20 @@ class UploadHandler(BaseHandler):
|
||||
|
||||
if user_id is None:
|
||||
logger.warning("User ID not found in upload handler call")
|
||||
console.warning("User ID not found in upload handler call")
|
||||
Console.warning("User ID not found in upload handler call")
|
||||
self.do_upload = False
|
||||
|
||||
if server_id is None:
|
||||
logger.warning("Server ID not found in upload handler call")
|
||||
console.warning("Server ID not found in upload handler call")
|
||||
Console.warning("Server ID not found in upload handler call")
|
||||
self.do_upload = False
|
||||
|
||||
if Enum_Permissions_Server.Files not in exec_user_server_permissions:
|
||||
if EnumPermissionsServer.FILES not in exec_user_server_permissions:
|
||||
logger.warning(
|
||||
f"User {user_id} tried to upload a file to "
|
||||
f"{server_id} without permissions!"
|
||||
)
|
||||
console.warning(
|
||||
Console.warning(
|
||||
f"User {user_id} tried to upload a file to "
|
||||
f"{server_id} without permissions!"
|
||||
)
|
||||
@ -88,8 +106,8 @@ class UploadHandler(BaseHandler):
|
||||
filename = self.request.headers.get("X-FileName", None)
|
||||
full_path = os.path.join(path, filename)
|
||||
|
||||
if not helper.in_path(
|
||||
helper.get_os_understandable_path(
|
||||
if not Helpers.in_path(
|
||||
Helpers.get_os_understandable_path(
|
||||
self.controller.servers.get_server_data_by_id(server_id)["path"]
|
||||
),
|
||||
full_path,
|
||||
@ -97,7 +115,7 @@ class UploadHandler(BaseHandler):
|
||||
print(
|
||||
user_id,
|
||||
server_id,
|
||||
helper.get_os_understandable_path(
|
||||
Helpers.get_os_understandable_path(
|
||||
self.controller.servers.get_server_data_by_id(server_id)["path"]
|
||||
),
|
||||
full_path,
|
||||
@ -106,7 +124,7 @@ class UploadHandler(BaseHandler):
|
||||
f"User {user_id} tried to upload a file to {server_id} "
|
||||
f"but the path is not inside of the server!"
|
||||
)
|
||||
console.warning(
|
||||
Console.warning(
|
||||
f"User {user_id} tried to upload a file to {server_id} "
|
||||
f"but the path is not inside of the server!"
|
||||
)
|
||||
@ -119,7 +137,7 @@ class UploadHandler(BaseHandler):
|
||||
logger.error(f"Upload failed with error: {e}")
|
||||
self.do_upload = False
|
||||
# If max_body_size is not set, you cannot upload files > 100MB
|
||||
self.request.connection.set_max_body_size(MAX_STREAMED_SIZE)
|
||||
self.request.connection.set_max_body_size(max_streamed_size)
|
||||
|
||||
def post(self):
|
||||
logger.info("Upload completed")
|
||||
@ -128,13 +146,13 @@ class UploadHandler(BaseHandler):
|
||||
if self.do_upload:
|
||||
time.sleep(5)
|
||||
if files_left == 0:
|
||||
websocket_helper.broadcast("close_upload_box", "success")
|
||||
self.helper.websocket_helper.broadcast("close_upload_box", "success")
|
||||
self.finish("success") # Nope, I'm sending "success"
|
||||
self.f.close()
|
||||
else:
|
||||
time.sleep(5)
|
||||
if files_left == 0:
|
||||
websocket_helper.broadcast("close_upload_box", "error")
|
||||
self.helper.websocket_helper.broadcast("close_upload_box", "error")
|
||||
self.finish("error")
|
||||
|
||||
def data_received(self, chunk):
|
||||
|
@ -2,16 +2,9 @@ import json
|
||||
import logging
|
||||
import asyncio
|
||||
from urllib.parse import parse_qsl
|
||||
import tornado.websocket
|
||||
|
||||
from app.classes.shared.authentication import authentication
|
||||
from app.classes.shared.helpers import helper
|
||||
from app.classes.web.websocket_helper import websocket_helper
|
||||
|
||||
try:
|
||||
import tornado.websocket
|
||||
|
||||
except ModuleNotFoundError as e:
|
||||
helper.auto_installer_fix(e)
|
||||
from app.classes.shared.helpers import Helpers
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@ -24,7 +17,10 @@ class SocketHandler(tornado.websocket.WebSocketHandler):
|
||||
translator = None
|
||||
io_loop = None
|
||||
|
||||
def initialize(self, controller=None, tasks_manager=None, translator=None):
|
||||
def initialize(
|
||||
self, helper=None, controller=None, tasks_manager=None, translator=None
|
||||
):
|
||||
self.helper = helper
|
||||
self.controller = controller
|
||||
self.tasks_manager = tasks_manager
|
||||
self.translator = translator
|
||||
@ -39,11 +35,11 @@ class SocketHandler(tornado.websocket.WebSocketHandler):
|
||||
return remote_ip
|
||||
|
||||
def get_user_id(self):
|
||||
_, _, user = authentication.check(self.get_cookie("token"))
|
||||
_, _, user = self.controller.authentication.check(self.get_cookie("token"))
|
||||
return user["user_id"]
|
||||
|
||||
def check_auth(self):
|
||||
return authentication.check_bool(self.get_cookie("token"))
|
||||
return self.controller.authentication.check_bool(self.get_cookie("token"))
|
||||
|
||||
# pylint: disable=arguments-differ
|
||||
def open(self):
|
||||
@ -51,7 +47,7 @@ class SocketHandler(tornado.websocket.WebSocketHandler):
|
||||
if self.check_auth():
|
||||
self.handle()
|
||||
else:
|
||||
websocket_helper.send_message(
|
||||
self.helper.websocket_helper.send_message(
|
||||
self, "notification", "Not authenticated for WebSocket connection"
|
||||
)
|
||||
self.close()
|
||||
@ -62,7 +58,7 @@ class SocketHandler(tornado.websocket.WebSocketHandler):
|
||||
"Someone tried to connect via WebSocket without proper authentication",
|
||||
self.get_remote_ip(),
|
||||
)
|
||||
websocket_helper.broadcast(
|
||||
self.helper.websocket_helper.broadcast(
|
||||
"notification",
|
||||
"Someone tried to connect via WebSocket without proper authentication",
|
||||
)
|
||||
@ -74,10 +70,10 @@ class SocketHandler(tornado.websocket.WebSocketHandler):
|
||||
self.page = self.get_query_argument("page")
|
||||
self.page_query_params = dict(
|
||||
parse_qsl(
|
||||
helper.remove_prefix(self.get_query_argument("page_query_params"), "?")
|
||||
Helpers.remove_prefix(self.get_query_argument("page_query_params"), "?")
|
||||
)
|
||||
)
|
||||
websocket_helper.add_client(self)
|
||||
self.helper.websocket_helper.add_client(self)
|
||||
logger.debug("Opened WebSocket connection")
|
||||
|
||||
# pylint: disable=arguments-renamed
|
||||
@ -89,7 +85,7 @@ class SocketHandler(tornado.websocket.WebSocketHandler):
|
||||
logger.debug(f"Event Type: {message['event']}, Data: {message['data']}")
|
||||
|
||||
def on_close(self):
|
||||
websocket_helper.remove_client(self)
|
||||
self.helper.websocket_helper.remove_client(self)
|
||||
logger.debug("Closed WebSocket connection")
|
||||
|
||||
async def write_message_int(self, message):
|
||||
|
@ -1,13 +1,14 @@
|
||||
import json
|
||||
import logging
|
||||
|
||||
from app.classes.shared.console import console
|
||||
from app.classes.shared.console import Console
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class WebSocketHelper:
|
||||
def __init__(self):
|
||||
def __init__(self, helper):
|
||||
self.helper = helper
|
||||
self.clients = set()
|
||||
|
||||
def add_client(self, client):
|
||||
@ -16,8 +17,9 @@ class WebSocketHelper:
|
||||
def remove_client(self, client):
|
||||
self.clients.remove(client)
|
||||
|
||||
# pylint: disable=no-self-use
|
||||
def send_message(self, client, event_type: str, data):
|
||||
def send_message(
|
||||
self, client, event_type: str, data
|
||||
): # pylint: disable=no-self-use
|
||||
if client.check_auth():
|
||||
message = str(json.dumps({"event": event_type, "data": data}))
|
||||
client.write_message_helper(message)
|
||||
@ -101,10 +103,7 @@ class WebSocketHelper:
|
||||
)
|
||||
|
||||
def disconnect_all(self):
|
||||
console.info("Disconnecting WebSocket clients")
|
||||
Console.info("Disconnecting WebSocket clients")
|
||||
for client in self.clients:
|
||||
client.close()
|
||||
console.info("Disconnected WebSocket clients")
|
||||
|
||||
|
||||
websocket_helper = WebSocketHelper()
|
||||
Console.info("Disconnected WebSocket clients")
|
||||
|
@ -1,20 +1,26 @@
|
||||
{
|
||||
"https": true,
|
||||
"http_port": 8000,
|
||||
"https_port": 8443,
|
||||
"language": "en_EN",
|
||||
"cookie_expire": 30,
|
||||
"cookie_secret": "random",
|
||||
"apikey_secret": "random",
|
||||
"show_errors": true,
|
||||
"history_max_age": 7,
|
||||
"stats_update_frequency": 30,
|
||||
"delete_default_json": false,
|
||||
"show_contribute_link": true,
|
||||
"virtual_terminal_lines": 70,
|
||||
"max_log_lines": 700,
|
||||
"max_audit_entries": 300,
|
||||
"disabled_language_files": ["lol_EN.json", ""],
|
||||
"keywords": ["help", "chunk"],
|
||||
"allow_nsfw_profile_pictures": false
|
||||
}
|
||||
"http_port": 8000,
|
||||
"https_port": 8443,
|
||||
"language": "en_EN",
|
||||
"cookie_expire": 30,
|
||||
"cookie_secret": "random",
|
||||
"apikey_secret": "random",
|
||||
"show_errors": true,
|
||||
"history_max_age": 7,
|
||||
"stats_update_frequency": 30,
|
||||
"delete_default_json": false,
|
||||
"show_contribute_link": true,
|
||||
"virtual_terminal_lines": 70,
|
||||
"max_log_lines": 700,
|
||||
"max_audit_entries": 300,
|
||||
"disabled_language_files": [
|
||||
"lol_EN.json",
|
||||
""
|
||||
],
|
||||
"stream_size_GB": 1,
|
||||
"keywords": [
|
||||
"help",
|
||||
"chunk"
|
||||
],
|
||||
"allow_nsfw_profile_pictures": false
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"major": 4,
|
||||
"minor": 0,
|
||||
"sub": 0,
|
||||
"meta": "alpha.3.5"
|
||||
}
|
||||
"sub": 0,
|
||||
"meta": "beta"
|
||||
}
|
@ -9,7 +9,7 @@
|
||||
|
||||
<div class="content-wrapper">
|
||||
|
||||
<!-- Page Title Header Starts-->
|
||||
<!-- Page Title Header Starts-->
|
||||
<div class="row page-title-header">
|
||||
<div class="col-12">
|
||||
<div class="page-header">
|
||||
@ -24,35 +24,39 @@
|
||||
<div class="card">
|
||||
<div class="card-header header-sm d-flex justify-content-between align-items-center">
|
||||
<h4 class="card-title"><i class="fas fa-history"></i> Audit Logs</h4>
|
||||
<span class="too_small" title="{{ translate('dashboard', 'cannotSeeOnMobile', data['lang']) }}", data-content="{{ translate('dashboard', 'cannotSeeOnMobile2', data['lang']) }}", data-placement="top"></span>
|
||||
{% if data['user_data']['hints'] %}
|
||||
<span class="too_small" title="{{ translate('dashboard', 'cannotSeeOnMobile', data['lang']) }}" ,
|
||||
data-content="{{ translate('dashboard', 'cannotSeeOnMobile2', data['lang']) }}" ,
|
||||
data-placement="top"></span>
|
||||
{% end %}
|
||||
</div>
|
||||
<div class="card-body">
|
||||
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover" id="audit_table" style="overflow: scroll;" width="100%">
|
||||
<thead>
|
||||
<tr class="rounded">
|
||||
<td>Username</td>
|
||||
<td>Time</td>
|
||||
<td>Action</td>
|
||||
<td>Server ID</td>
|
||||
<td>IP</td>
|
||||
</tr>
|
||||
<tr class="rounded">
|
||||
<td>Username</td>
|
||||
<td>Time</td>
|
||||
<td>Action</td>
|
||||
<td>Server ID</td>
|
||||
<td>IP</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for row in data['audit_logs'] %}
|
||||
<tr>
|
||||
{% for row in data['audit_logs'] %}
|
||||
<tr>
|
||||
<td>{{ row['user_name'] }}</td>
|
||||
<td>
|
||||
{{ row['created'].strftime('%Y-%m-%d %H:%M:%S') }}
|
||||
{{ row['created'].strftime('%Y-%m-%d %H:%M:%S') }}
|
||||
</td>
|
||||
<td>{{ row['log_msg'] }}</td>
|
||||
<td>{{ row['server_id'] }}</td>
|
||||
<td>{{ row['source_ip'] }}</td>
|
||||
</tr>
|
||||
{% end %}
|
||||
</tr>
|
||||
{% end %}
|
||||
</tbody>
|
||||
</table>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
@ -60,9 +64,10 @@
|
||||
</div>
|
||||
</div>
|
||||
<style>
|
||||
.popover-body{
|
||||
color: white !important;;
|
||||
}
|
||||
.popover-body {
|
||||
color: white !important;
|
||||
;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
@ -76,37 +81,37 @@
|
||||
{% block js %}
|
||||
<script>
|
||||
|
||||
$( document ).ready(function() {
|
||||
$(document).ready(function () {
|
||||
console.log('ready for JS!')
|
||||
$('#audit_table').DataTable({
|
||||
'order': [1, 'desc']
|
||||
}
|
||||
);
|
||||
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<script>
|
||||
$(document).ready(function(){
|
||||
$(document).ready(function () {
|
||||
$('[data-toggle="popover"]').popover();
|
||||
if($(window).width() < 1000){
|
||||
if ($(window).width() < 1000) {
|
||||
$('.too_small').popover("show");
|
||||
}
|
||||
|
||||
});
|
||||
$(window).ready(function(){
|
||||
$('body').click(function(){
|
||||
$('.too_small').popover("hide");
|
||||
});
|
||||
$(window).ready(function () {
|
||||
$('body').click(function () {
|
||||
$('.too_small').popover("hide");
|
||||
});
|
||||
});
|
||||
$(window).resize(function() {
|
||||
$(window).resize(function () {
|
||||
// This will execute whenever the window is resized
|
||||
if($(window).width() < 1000){
|
||||
if ($(window).width() < 1000) {
|
||||
$('.too_small').popover("show");
|
||||
}
|
||||
else{
|
||||
else {
|
||||
$('.too_small').popover("hide");
|
||||
} // New width
|
||||
});
|
||||
</script>
|
||||
</script>
|
||||
|
||||
{% end %}
|
@ -75,7 +75,8 @@
|
||||
<h3 class="mb-0 font-weight-semibold" id="total_players">{{ data['num_players'] }}</h3>
|
||||
</div>
|
||||
<div class="wrapper my-auto ml-auto ml-lg-4">
|
||||
<p class="mb-0 text-warning"><span id="max_players">0</span> {{ translate('dashboard', 'max', data['lang']) }}</p>
|
||||
<p class="mb-0 text-warning"><span id="max_players">0</span> {{ translate('dashboard', 'max',
|
||||
data['lang']) }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -92,10 +93,12 @@
|
||||
<h4 class="card-title"><i class="fas fa-server"></i> {{ translate('dashboard', 'allServers',
|
||||
data['lang']) }}</h4>
|
||||
{% if len(data['servers']) > 0 %}
|
||||
{% if data['user_data']['hints'] %}
|
||||
<span class="too_small" title="{{ translate('dashboard', 'cannotSeeOnMobile', data['lang']) }}" ,
|
||||
data-content="{{ translate('dashboard', 'cannotSeeOnMobile2', data['lang']) }}" ,
|
||||
data-placement="top"></span>
|
||||
{% end %}
|
||||
{% end %}
|
||||
<div><a class="nav-link" href="/server/step1"><i class="fas fa-plus-circle"></i> {{
|
||||
translate('dashboard', 'newServer', data['lang']) }}</a></div>
|
||||
</div>
|
||||
@ -230,7 +233,9 @@
|
||||
data['lang']) }} <br />
|
||||
|
||||
{% if server['stats']['desc'] != 'False' %}
|
||||
<div id="desc_id" style="overflow-wrap: break-word !important; max-width: 85px !important; overflow: scroll;">{{ server['stats']['desc'] }}</div> <br />
|
||||
<div id="desc_id"
|
||||
style="overflow-wrap: break-word !important; max-width: 85px !important; overflow: scroll;">{{
|
||||
server['stats']['desc'] }}</div> <br />
|
||||
{% end %}
|
||||
|
||||
{% if server['stats']['version'] != 'False' %}
|
||||
@ -251,7 +256,8 @@
|
||||
data['lang']) }}</span>
|
||||
{% end %}
|
||||
</td>
|
||||
<span class="server-player-totals" id="server_players_{{server['server_data']['server_id']}}" data-players="{{ server['stats']['online']}}" data-max="{{ server['stats']['max'] }}"></span>
|
||||
<span class="server-player-totals" id="server_players_{{server['server_data']['server_id']}}"
|
||||
data-players="{{ server['stats']['online']}}" data-max="{{ server['stats']['max'] }}"></span>
|
||||
</tr>
|
||||
{% end %}
|
||||
</tbody>
|
||||
@ -754,11 +760,15 @@
|
||||
$(".clone_button").click(function () {
|
||||
server_id = $(this).attr("data-id");
|
||||
send_command(server_id, 'clone_server');
|
||||
bootbox.alert({
|
||||
bootbox.dialog({
|
||||
backdrop: true,
|
||||
title: '{% raw translate("dashboard", "sendingCommand", data["lang"]) %}',
|
||||
message: '<div align="center"><i class="fas fa-spin fa-spinner"></i> {% raw translate("dashboard", "bePatientClone", data["lang"]) %} </div>'
|
||||
message: '<div align="center"><i class="fas fa-spin fa-spinner"></i> {% raw translate("dashboard", "bePatientClone", data["lang"]) %} </div>',
|
||||
closeButton: false,
|
||||
});
|
||||
setTimeout(function () {
|
||||
location.reload();
|
||||
}, 5000)
|
||||
});
|
||||
|
||||
});
|
||||
@ -798,7 +808,7 @@
|
||||
|
||||
$(document).on("mousedown keyup click", function (event) {
|
||||
const value = $('.dataTables_filter input').val();
|
||||
const is_mobile = $('#mobile').css('display') == 'none';
|
||||
const is_mobile = $('#mobile').css('display') === 'none';
|
||||
|
||||
if ($("table#servers_table tbody").sortable("toArray").length > 1 && value === '' && !is_mobile) {
|
||||
$("table#servers_table tbody").sortable("enable");
|
||||
@ -857,7 +867,7 @@
|
||||
|
||||
// Fixes the appearance of a scrollbar when a user tries to drag an item too low
|
||||
// Disabled on mobile since sorting is disabled on mobile
|
||||
if ($('#mobile').css('display') != 'none') {
|
||||
if ($('#mobile').css('display') !== 'none') {
|
||||
$("div#servers_table_wrapper").css({ overflow: "hidden" });
|
||||
}
|
||||
});
|
||||
|
@ -9,11 +9,11 @@
|
||||
|
||||
<div class="content-wrapper">
|
||||
|
||||
<!-- Page Title Header Starts-->
|
||||
<!-- Page Title Header Starts-->
|
||||
<div class="row page-title-header">
|
||||
<div class="col-12">
|
||||
<div class="page-header">
|
||||
<!-- TODO: Translate the following -->
|
||||
<!-- TODO: Translate the following -->
|
||||
<h4 class="page-title">{{ translate('panelConfig', 'pageTitle', data['lang']) }}</h4>
|
||||
</div>
|
||||
</div>
|
||||
@ -30,11 +30,16 @@
|
||||
<div class="col-md-12 col-lg-12 grid-margin stretch-card">
|
||||
<div class="card">
|
||||
<div class="card-header header-sm d-flex justify-content-between align-items-center">
|
||||
<h4 class="card-title"><i class="fas fa-users"></i> {{ translate('panelConfig', 'users', data['lang']) }}</h4>
|
||||
<span class="too_small" title="{{ translate('dashboard', 'cannotSee', data['lang']) }}", data-content="{{ translate('dashboard', 'cannotSeeOnMobile2', data['lang']) }}", data-placement="top"></span>
|
||||
|
||||
<h4 class="card-title"><i class="fas fa-users"></i> {{ translate('panelConfig', 'users', data['lang'])
|
||||
}}</h4>
|
||||
{% if data['user_data']['hints'] %}
|
||||
<span class="too_small" title="{{ translate('dashboard', 'cannotSee', data['lang']) }}" ,
|
||||
data-content="{{ translate('dashboard', 'cannotSeeOnMobile2', data['lang']) }}" ,
|
||||
data-placement="top"></span>
|
||||
{% end %}
|
||||
<!-- TODO: Translate the following -->
|
||||
<div><a class="nav-link" href="/panel/add_user"><i class="fas fa-plus-circle"></i> {{ translate('panelConfig', 'newUser', data['lang']) }}</a></div>
|
||||
<div><a class="nav-link" href="/panel/add_user"><i class="fas fa-plus-circle"></i> {{
|
||||
translate('panelConfig', 'newUser', data['lang']) }}</a></div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
@ -50,38 +55,38 @@
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for user in data['users'] %}
|
||||
{% for user in data['users'] %}
|
||||
<tr>
|
||||
<td><i class="fas fa-user"></i> {{ user.username }}</td>
|
||||
<td>
|
||||
{% if user.enabled %}
|
||||
<span class="text-success">
|
||||
<i class="fas fa-check-square"></i> Yes
|
||||
</span>
|
||||
<span class="text-success">
|
||||
<i class="fas fa-check-square"></i> Yes
|
||||
</span>
|
||||
{% else %}
|
||||
<span class="text-danger">
|
||||
<i class="far fa-times-square"></i> No
|
||||
</span>
|
||||
<span class="text-danger">
|
||||
<i class="far fa-times-square"></i> No
|
||||
</span>
|
||||
|
||||
{% end %}
|
||||
</td>
|
||||
<td id="server_list_{{user.user_id}}">
|
||||
<ul id="{{user.user_id}}">
|
||||
<ul id="{{user.user_id}}">
|
||||
{% for item in data['auth-servers'][user.user_id] %}
|
||||
<li>{{item}}</li>
|
||||
<li>{{item}}</li>
|
||||
{% end %}
|
||||
</ul>
|
||||
</td>
|
||||
<td id="role_list_{{user.user_id}}">
|
||||
<ul>
|
||||
{% for item in data['user-roles'][user.user_id] %}
|
||||
{% for item in data['user-roles'][user.user_id] %}
|
||||
<li data-toggle="tooltip" title="{{ item }}">{{item}}</li>
|
||||
{% end %}
|
||||
{% end %}
|
||||
</ul>
|
||||
</td>
|
||||
<td><a href="/panel/edit_user?id={{user.user_id}}"><i class="fas fa-pencil-alt"></i></a></td>
|
||||
</tr>
|
||||
{% end %}
|
||||
{% end %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
@ -93,9 +98,15 @@
|
||||
<div class="col-md-12 col-lg-12 grid-margin stretch-card">
|
||||
<div class="card">
|
||||
<div class="card-header header-sm d-flex justify-content-between align-items-center">
|
||||
<h4 class="card-title"><i class="fas fa-user-tag"></i> {{ translate('panelConfig', 'roles', data['lang']) }}</h4>
|
||||
<span class="too_small2" title="{{ translate('dashboard', 'cannotSee', data['lang']) }}", data-content="{{ translate('dashboard', 'cannotSeeOnMobile2', data['lang']) }}", data-placement="top"></span>
|
||||
<div><a class="nav-link" href="/panel/add_role"><i class="fas fa-plus-circle"></i> {{ translate('panelConfig', 'newRole', data['lang']) }}</a></div>
|
||||
<h4 class="card-title"><i class="fas fa-user-tag"></i> {{ translate('panelConfig', 'roles',
|
||||
data['lang']) }}</h4>
|
||||
{% if data['user_data']['hints'] %}
|
||||
<span class="too_small2" title="{{ translate('dashboard', 'cannotSee', data['lang']) }}" ,
|
||||
data-content="{{ translate('dashboard', 'cannotSeeOnMobile2', data['lang']) }}" ,
|
||||
data-placement="top"></span>
|
||||
{% end %}
|
||||
<div><a class="nav-link" href="/panel/add_role"><i class="fas fa-plus-circle"></i> {{
|
||||
translate('panelConfig', 'newRole', data['lang']) }}</a></div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
@ -110,7 +121,7 @@
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for role in data['roles'] %}
|
||||
{% for role in data['roles'] %}
|
||||
<tr>
|
||||
<td>{{ role.role_name }}</td>
|
||||
<td id="role_list_{{role.role_id}}">
|
||||
@ -120,19 +131,20 @@
|
||||
{% end %}
|
||||
</ul>
|
||||
</td>
|
||||
<td><ul>
|
||||
{% for user in data['users'] %}
|
||||
<td>
|
||||
<ul>
|
||||
{% for user in data['users'] %}
|
||||
{% for ruser in data['user-roles'][user.user_id] %}
|
||||
{% if ruser == role.role_name %}
|
||||
<li>{{ user.username }}</li>
|
||||
{% end %}
|
||||
{% end %}
|
||||
{% end %}
|
||||
</ul>
|
||||
{% if ruser == role.role_name %}
|
||||
<li>{{ user.username }}</li>
|
||||
{% end %}
|
||||
{% end %}
|
||||
{% end %}
|
||||
</ul>
|
||||
</td>
|
||||
<td><a href="/panel/edit_role?id={{role.role_id}}"><i class="fas fa-pencil-alt"></i></a></td>
|
||||
</tr>
|
||||
{% end %}
|
||||
{% end %}
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
@ -146,10 +158,12 @@
|
||||
<div class="col-md-12 col-lg-12 grid-margin stretch-card">
|
||||
<div class="card">
|
||||
<div class="card-header header-sm d-flex justify-content-between align-items-center">
|
||||
<h4 class="card-title"><i class="fas fa-user-tag"></i> {{ translate('panelConfig', 'adminControls', data['lang']) }}</h4>
|
||||
<h4 class="card-title"><i class="fas fa-user-tag"></i> {{ translate('panelConfig', 'adminControls',
|
||||
data['lang']) }}</h4>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<button type="button" class="btn btn-outline-danger clear-comm">{{ translate('panelConfig', 'clearComms', data['lang']) }}</button>
|
||||
<button type="button" class="btn btn-outline-danger clear-comm">{{ translate('panelConfig',
|
||||
'clearComms', data['lang']) }}</button>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
@ -165,9 +179,10 @@
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.popover-body{
|
||||
color: white !important;;
|
||||
}
|
||||
.popover-body {
|
||||
color: white !important;
|
||||
;
|
||||
}
|
||||
</style>
|
||||
<!-- content-wrapper ends -->
|
||||
|
||||
@ -175,46 +190,46 @@
|
||||
|
||||
{% block js %}
|
||||
<script>
|
||||
$(document).ready(function(){
|
||||
$('[data-toggle="popover"]').popover();
|
||||
if($(window).width() < 1000){
|
||||
$('.too_small').popover("show");
|
||||
$('.too_small2').popover("show");
|
||||
}
|
||||
$(document).ready(function () {
|
||||
$('[data-toggle="popover"]').popover();
|
||||
if ($(window).width() < 1000) {
|
||||
$('.too_small').popover("show");
|
||||
$('.too_small2').popover("show");
|
||||
}
|
||||
|
||||
});
|
||||
$(window).ready(function(){
|
||||
$('body').click(function(){
|
||||
$('.too_small').popover("hide");
|
||||
$('.too_small2').popover("hide");
|
||||
});
|
||||
$(window).ready(function () {
|
||||
$('body').click(function () {
|
||||
$('.too_small').popover("hide");
|
||||
$('.too_small2').popover("hide");
|
||||
});
|
||||
});
|
||||
$(window).resize(function() {
|
||||
// This will execute whenever the window is resized
|
||||
if($(window).width() < 1000){
|
||||
$('.too_small').popover("show");
|
||||
}
|
||||
else{
|
||||
$('.too_small').popover("hide");
|
||||
} // New width
|
||||
if($(window).width() < 1000){
|
||||
$('.too_small2').popover("show");
|
||||
}
|
||||
else{
|
||||
$('.too_small2').popover("hide");
|
||||
} // New width
|
||||
});
|
||||
});
|
||||
$(window).resize(function () {
|
||||
// This will execute whenever the window is resized
|
||||
if ($(window).width() < 1000) {
|
||||
$('.too_small').popover("show");
|
||||
}
|
||||
else {
|
||||
$('.too_small').popover("hide");
|
||||
} // New width
|
||||
if ($(window).width() < 1000) {
|
||||
$('.too_small2').popover("show");
|
||||
}
|
||||
else {
|
||||
$('.too_small2').popover("hide");
|
||||
} // New width
|
||||
});
|
||||
</script>
|
||||
<script>
|
||||
|
||||
$( document ).ready(function() {
|
||||
console.log('ready for JS!')
|
||||
$(document).ready(function () {
|
||||
console.log('ready for JS!')
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
$( ".show_button" ).click(function() {
|
||||
$(".show_button").click(function () {
|
||||
console.log("showing key");
|
||||
api_key = $(this).attr("data-id");
|
||||
api_key = $(this).attr("data-id");
|
||||
bootbox.alert({
|
||||
backdrop: true,
|
||||
title: '',
|
||||
@ -225,13 +240,13 @@ $( document ).ready(function() {
|
||||
$('.clear-comm').click(function () {
|
||||
var token = getCookie("_xsrf")
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
headers: {'X-XSRFToken': token},
|
||||
url: '/ajax/clear_comm',
|
||||
success: function (data) {
|
||||
},
|
||||
type: "POST",
|
||||
headers: { 'X-XSRFToken': token },
|
||||
url: '/ajax/clear_comm',
|
||||
success: function (data) {
|
||||
},
|
||||
});
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
{% end %}
|
@ -9,22 +9,22 @@
|
||||
|
||||
<div class="content-wrapper">
|
||||
|
||||
<!-- Page Title Header Starts-->
|
||||
<!-- Page Title Header Starts-->
|
||||
<div class="row page-title-header">
|
||||
<div class="col-12">
|
||||
<div class="page-header">
|
||||
{% if data['new_user'] %}
|
||||
<h4 class="page-title">
|
||||
{{ translate('userConfig', 'pageTitleNew', data['lang']) }}
|
||||
<br />
|
||||
<small>UID: N/A</small>
|
||||
</h4>
|
||||
<h4 class="page-title">
|
||||
{{ translate('userConfig', 'pageTitleNew', data['lang']) }}
|
||||
<br />
|
||||
<small>UID: N/A</small>
|
||||
</h4>
|
||||
{% else %}
|
||||
<h4 class="page-title">
|
||||
{{ translate('userConfig', 'pageTitle', data['lang']) }} - {{ data['user']['user_id'] }}
|
||||
<br />
|
||||
<small>UID: {{ data['user']['user_id'] }}</small>
|
||||
</h4>
|
||||
<h4 class="page-title">
|
||||
{{ translate('userConfig', 'pageTitle', data['lang']) }}
|
||||
<br />
|
||||
<small>UID: {{ data['user']['user_id'] }}</small>
|
||||
</h4>
|
||||
{% end %}
|
||||
</div>
|
||||
</div>
|
||||
@ -37,198 +37,250 @@
|
||||
<div class="col-sm-12 grid-margin">
|
||||
<div class="card">
|
||||
<div class="card-body pt-0">
|
||||
<ul class="nav nav-tabs col-md-12 tab-simple-styled " role="tablist">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" href="/panel/{{ 'add_user' if data['new_user'] else 'edit_user' }}?id={{ data['user']['user_id'] }}&subpage=config" role="tab" aria-selected="true">
|
||||
<i class="fas fa-cogs"></i> {{ translate('userConfig', 'config', data['lang']) }} - {{ data['user']['user_id'] }}</a>
|
||||
</li>
|
||||
{% if not data['new_user'] %}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/panel/edit_user_apikeys?id={{ data['user']['user_id'] }}" role="tab" aria-selected="false">
|
||||
<i class="fas fa-key"></i>{{ translate('userConfig', 'apiKey', data['lang']) }} - {{ data['user']['user_id'] }}</a>
|
||||
</li>
|
||||
{% end %}
|
||||
</ul>
|
||||
<ul class="nav nav-tabs col-md-12 tab-simple-styled " role="tablist">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active"
|
||||
href="/panel/{{ 'add_user' if data['new_user'] else 'edit_user' }}?id={{ data['user']['user_id'] }}&subpage=config"
|
||||
role="tab" aria-selected="true">
|
||||
<i class="fas fa-cogs"></i> {{ translate('userConfig', 'config', data['lang']) }}</a>
|
||||
</li>
|
||||
{% if not data['new_user'] %}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/panel/edit_user_apikeys?id={{ data['user']['user_id'] }}" role="tab"
|
||||
aria-selected="false">
|
||||
<i class="fas fa-key"></i>{{ translate('userConfig', 'apiKey', data['lang']) }}</a>
|
||||
</li>
|
||||
{% end %}
|
||||
</ul>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6 col-sm-12">
|
||||
{% if data['new_user'] %}
|
||||
<form id="user_form" class="forms-sample" method="post" action="/panel/add_user">
|
||||
{% else %}
|
||||
<form id="user_form" class="forms-sample" method="post" action="/panel/edit_user">
|
||||
<div class="row">
|
||||
<div class="col-md-6 col-sm-12">
|
||||
{% if data['new_user'] %}
|
||||
<form id="user_form" class="forms-sample" method="post" action="/panel/add_user">
|
||||
{% else %}
|
||||
<form id="user_form" class="forms-sample" method="post" action="/panel/edit_user">
|
||||
{% end %}
|
||||
{% raw xsrf_form_html() %}
|
||||
<input type="hidden" name="id" value="{{ data['user']['user_id'] }}">
|
||||
<input type="hidden" name="subpage" value="config">
|
||||
{% raw xsrf_form_html() %}
|
||||
<input type="hidden" name="id" value="{{ data['user']['user_id'] }}">
|
||||
<input type="hidden" name="subpage" value="config">
|
||||
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header header-sm d-flex justify-content-between align-items-center">
|
||||
<h4 class="card-title"><i class="fas fa-user"></i> {{ translate('userConfig', 'userSettings', data['lang']) }} - {{ data['user']['user_id'] }}</h4>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="username">{{ translate('userConfig', 'userName', data['lang']) }} - {{ data['user']['user_id'] }}<small class="text-muted ml-1"> - {{ translate('userConfig', 'userNameDesc', data['lang']) }} - {{ data['user']['user_id'] }}</small> </label>
|
||||
<input type="text" class="form-control" name="username" id="username" value="{{ data['user']['username'] }}" placeholder="User Name" >
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="password0">{{ translate('userConfig', 'password', data['lang']) }} - {{ data['user']['user_id'] }}<small class="text-muted ml-1"> - {{ translate('userConfig', 'leaveBlank', data['lang']) }} - {{ data['user']['user_id'] }}</small> </label>
|
||||
<input type="password" class="form-control" name="password0" id="password0" value="" placeholder="Password" >
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="password1">{{ translate('userConfig', 'repeat', data['lang']) }} - {{ data['user']['user_id'] }} <small class="text-muted ml-1"> - {{ translate('userConfig', 'leaveBlank', data['lang']) }} - {{ data['user']['user_id'] }}</small> </label>
|
||||
<input type="password" class="form-control" name="password1" id="password1" value="" placeholder="Repeat Password" >
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="email">{{ translate('userConfig', 'gravEmail', data['lang']) }} - {{ data['user']['user_id'] }}<small class="text-muted ml-1"> - {{ translate('userConfig', 'gravDesc', data['lang']) }} - {{ data['user']['user_id'] }}</small> </label>
|
||||
<input type="email" class="form-control" name="email" id="email" value="{{ data['user']['email'] }}" placeholder="Gravatar Email" >
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="language">{{ translate('userConfig', 'userLang', data['lang']) }}</label>
|
||||
<select class="form-select form-control form-control-lg select-css" id="language" name="language" form="user_form">
|
||||
{% for lang in data['languages'] %}
|
||||
{% if not 'incomplete' in lang %}
|
||||
<option value="{{lang}}">{{lang}}</option>
|
||||
{% else %}
|
||||
<option value="{{lang}}" disabled>{{lang}}</option>
|
||||
{% end %}
|
||||
{% end %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-header header-sm d-flex justify-content-between align-items-center">
|
||||
<h4 class="card-title"><i class="fas fa-user"></i> {{ translate('userConfig', 'userSettings',
|
||||
data['lang']) }}</h4>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="username">{{ translate('userConfig', 'userName', data['lang'])
|
||||
}}<small class="text-muted ml-1"> - {{ translate('userConfig', 'userNameDesc', data['lang'])
|
||||
}}</small> </label>
|
||||
<input type="text" class="form-control" name="username" id="username"
|
||||
value="{{ data['user']['username'] }}" placeholder="User Name">
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header header-sm d-flex justify-content-between align-items-center">
|
||||
<h4 class="card-title"><i class="fas fa-user-tag"></i> {{ translate('userConfig', 'userRoles', data['lang']) }} <small class="text-muted ml-1"> - {{ translate('userConfig', 'userRolesDesc', data['lang']) }}</small></h4>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="form-group">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr class="rounded">
|
||||
<th>{{ translate('userConfig', 'roleName', data['lang']) }}</th>
|
||||
<th>{{ translate('userConfig', 'member', data['lang']) }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for role in data['roles_all'] %}
|
||||
<tr>
|
||||
<td>{{ role.role_name }}</td>
|
||||
<td>
|
||||
{% if role.role_id in data['user']['roles'] %}
|
||||
<input type="checkbox" class="form-check-input" id="role_{{ role.role_id }}_membership" name="role_{{ role.role_id }}_membership" checked="" value="1">
|
||||
{% else %}
|
||||
<input type="checkbox" class="form-check-input" id="role_{{ role.role_id }}_membership" name="role_{{ role.role_id }}_membership" value="1">
|
||||
{% end %}
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
{% end %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="password0">{{ translate('userConfig', 'password', data['lang'])
|
||||
}}<small class="text-muted ml-1"> - {{ translate('userConfig', 'leaveBlank', data['lang']) }}
|
||||
</small> </label>
|
||||
<input type="password" class="form-control" name="password0" id="password0" value=""
|
||||
placeholder="Password">
|
||||
</div>
|
||||
|
||||
<!-- Put Permissions Crafty part here -->
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header header-sm d-flex justify-content-between align-items-center">
|
||||
<h4 class="card-title"><i class="fas fa-user-lock"></i> {{ translate('userConfig', 'craftyPerms', data['lang']) }} <small class="text-muted ml-1"> - {{ translate('userConfig', 'craftyPermDesc', data['lang']) }}</small></h4>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="form-group">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr class="rounded">
|
||||
<th>{{ translate('userConfig', 'permName', data['lang']) }}</th>
|
||||
<th>{{ translate('userConfig', 'auth', data['lang']) }}</th>
|
||||
<th>{{ translate('userConfig', 'uses', data['lang']) }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for permission in data['permissions_all'] %}
|
||||
<tr>
|
||||
<td>{{ permission.name }}</td>
|
||||
<td>
|
||||
{% if permission in data['permissions_list'] %}
|
||||
<input type="checkbox" class="form-check-input" id="permission_{{ permission.name }}" name="permission_{{ permission.name }}" checked="" value="1">
|
||||
{% else %}
|
||||
<input type="checkbox" class="form-check-input" id="permission_{{ permission.name }}" name="permission_{{ permission.name }}" value="1">
|
||||
{% end %}
|
||||
</td>
|
||||
<td><input type="text" class="form-control" name="quantity_{{ permission.name }}" id="quantity_{{ permission.name }}" value="{{ data['quantity_server'][permission.name] }}"></td>
|
||||
</tr>
|
||||
{% end %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="password1">{{ translate('userConfig', 'repeat', data['lang']) }}
|
||||
<small class="text-muted ml-1"> - {{ translate('userConfig', 'leaveBlank', data['lang'])
|
||||
}}</small> </label>
|
||||
<input type="password" class="form-control" name="password1" id="password1" value=""
|
||||
placeholder="Repeat Password">
|
||||
</div>
|
||||
|
||||
<div class="form-check-flat">
|
||||
<label for="enabled" class="form-check-label ml-4 mb-4">
|
||||
{% if data['user']['enabled'] %}
|
||||
<input type="checkbox" class="form-check-input" id="enabled" name="enabled" checked="" value="1">{{ translate('userConfig', 'enabled', data['lang']) }}
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="email">{{ translate('userConfig', 'gravEmail', data['lang'])
|
||||
}}<small class="text-muted ml-1"> - {{ translate('userConfig', 'gravDesc', data['lang'])
|
||||
}}</small> </label>
|
||||
<input type="email" class="form-control" name="email" id="email"
|
||||
value="{{ data['user']['email'] }}" placeholder="Gravatar Email">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label" for="language">{{ translate('userConfig', 'userLang', data['lang'])
|
||||
}}</label>
|
||||
<select class="form-select form-control form-control-lg select-css" id="language"
|
||||
name="language" form="user_form">
|
||||
{% for lang in data['languages'] %}
|
||||
{% if not 'incomplete' in lang %}
|
||||
<option value="{{lang}}">{{lang}}</option>
|
||||
{% else %}
|
||||
<input type="checkbox" class="form-check-input" id="enabled" name="enabled" value="1">{{ translate('userConfig', 'enabled', data['lang']) }}
|
||||
<option value="{{lang}}" disabled>{{lang}}</option>
|
||||
{% end %}
|
||||
</label>
|
||||
|
||||
<label for="superuser" class="form-check-label ml-4 mb-4">
|
||||
{% if data['user']['superuser'] %}
|
||||
<input type="checkbox" onclick="superConfirm()" class="form-check-input" id="superuser" name="superuser" checked="" value="1" {{ data['super-disabled'] }} >{{ translate('userConfig', 'super', data['lang']) }}
|
||||
{% else %}
|
||||
<input type="checkbox" onclick="superConfirm()" class="form-check-input" id="superuser" name="superuser" {{ data['super-disabled'] }} value="1" >{{ translate('userConfig', 'super', data['lang']) }}
|
||||
{% end %}
|
||||
</label>
|
||||
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-success mr-2"><i class="fas fa-save"></i> {{ translate('panelConfig', 'save', data['lang']) }}</button>
|
||||
<button type="reset" onclick="location.href='/panel/panel_config'" class="btn btn-light"><i class="fas fa-undo-alt"></i> {{ translate('panelConfig', 'cancel', data['lang']) }}</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6 col-sm-12">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h4 class="card-title"><i class="fas fa-user-cog"></i> {{ translate('userConfig', 'configArea', data['lang']) }}</h4>
|
||||
<p class="card-description"> {{ translate('userConfig', 'configAreaDesc', data['lang']) }}</p>
|
||||
<blockquote class="blockquote">
|
||||
<p class="mb-0">
|
||||
{{ translate('userConfig', 'created', data['lang']) }} {{ str(data['user']['created']) }}
|
||||
<br />
|
||||
{{ translate('userConfig', 'lastLogin', data['lang']) }} {{ str(data['user']['last_login']) }}
|
||||
<br />
|
||||
{{ translate('userConfig', 'lastUpdate', data['lang']) }} {{ str(data['user']['last_update']) }}
|
||||
<br />
|
||||
{{ translate('userConfig', 'lastIP', data['lang']) }} {{ data['user']['last_ip'] }}
|
||||
<br />
|
||||
</p>
|
||||
</blockquote>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
{% if data['new_user'] %}
|
||||
<a class="btn btn-sm btn-danger disabled"><i class="fas fa-trash"></i>{{ translate('userConfig', 'deleteUserB', data['lang']) }}</a><br />
|
||||
<small>{{ translate('userConfig', 'notExist', data['lang']) }}</small>
|
||||
{% elif data['user']['superuser'] %}
|
||||
<a class="btn btn-sm btn-danger disabled"><i class="fas fa-trash"></i> {{ translate('userConfig', 'deleteUserB', data['lang']) }}</a><br />
|
||||
<small>{{ translate('userConfig', 'delSuper', data['lang']) }}</small>
|
||||
{% else %}
|
||||
<button class="btn btn-sm btn-danger delete-user"><i class="fas fa-trash"></i> {{ translate('userConfig', 'deleteUserB', data['lang']) }}</a>
|
||||
{% end %}
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header header-sm d-flex justify-content-between align-items-center">
|
||||
<h4 class="card-title"><i class="fas fa-user-tag"></i> {{ translate('userConfig', 'userRoles',
|
||||
data['lang']) }} <small class="text-muted ml-1"> - {{ translate('userConfig', 'userRolesDesc',
|
||||
data['lang']) }}</small></h4>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="form-group">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr class="rounded">
|
||||
<th>{{ translate('userConfig', 'roleName', data['lang']) }}</th>
|
||||
<th>{{ translate('userConfig', 'member', data['lang']) }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for role in data['roles_all'] %}
|
||||
<tr>
|
||||
<td>{{ role.role_name }}</td>
|
||||
<td>
|
||||
{% if role.role_id in data['user']['roles'] %}
|
||||
<input type="checkbox" class="form-check-input"
|
||||
id="role_{{ role.role_id }}_membership" name="role_{{ role.role_id }}_membership"
|
||||
checked="" value="1">
|
||||
{% else %}
|
||||
<input type="checkbox" class="form-check-input"
|
||||
id="role_{{ role.role_id }}_membership" name="role_{{ role.role_id }}_membership"
|
||||
value="1">
|
||||
{% end %}
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
{% end %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Put Permissions Crafty part here -->
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header header-sm d-flex justify-content-between align-items-center">
|
||||
<h4 class="card-title"><i class="fas fa-user-lock"></i> {{ translate('userConfig', 'craftyPerms',
|
||||
data['lang']) }} <small class="text-muted ml-1"> - {{ translate('userConfig', 'craftyPermDesc',
|
||||
data['lang']) }}</small></h4>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="form-group">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr class="rounded">
|
||||
<th>{{ translate('userConfig', 'permName', data['lang']) }}</th>
|
||||
<th>{{ translate('userConfig', 'auth', data['lang']) }}</th>
|
||||
<th>{{ translate('userConfig', 'uses', data['lang']) }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for permission in data['permissions_all'] %}
|
||||
<tr>
|
||||
<td>{{ permission.name }}</td>
|
||||
<td>
|
||||
{% if permission in data['permissions_list'] %}
|
||||
<input type="checkbox" class="form-check-input" id="permission_{{ permission.name }}"
|
||||
name="permission_{{ permission.name }}" checked="" value="1">
|
||||
{% else %}
|
||||
<input type="checkbox" class="form-check-input" id="permission_{{ permission.name }}"
|
||||
name="permission_{{ permission.name }}" value="1">
|
||||
{% end %}
|
||||
</td>
|
||||
<td><input type="text" class="form-control" name="quantity_{{ permission.name }}"
|
||||
id="quantity_{{ permission.name }}"
|
||||
value="{{ data['quantity_server'][permission.name] }}"></td>
|
||||
</tr>
|
||||
{% end %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-check-flat">
|
||||
<label for="enabled" class="form-check-label ml-4 mb-4">
|
||||
{% if data['user']['enabled'] %}
|
||||
<input type="checkbox" class="form-check-input" id="enabled" name="enabled" checked=""
|
||||
value="1">{{ translate('userConfig', 'enabled', data['lang']) }}
|
||||
{% else %}
|
||||
<input type="checkbox" class="form-check-input" id="enabled" name="enabled" value="1">{{
|
||||
translate('userConfig', 'enabled', data['lang']) }}
|
||||
{% end %}
|
||||
</label>
|
||||
|
||||
<label for="superuser" class="form-check-label ml-4 mb-4">
|
||||
{% if data['user']['superuser'] %}
|
||||
<input type="checkbox" onclick="superConfirm()" class="form-check-input" id="superuser"
|
||||
name="superuser" checked="" value="1" {{ data['super-disabled'] }}>{{ translate('userConfig',
|
||||
'super', data['lang']) }}
|
||||
{% else %}
|
||||
<input type="checkbox" onclick="superConfirm()" class="form-check-input" id="superuser"
|
||||
name="superuser" {{ data['super-disabled'] }} value="1">{{ translate('userConfig', 'super',
|
||||
data['lang']) }}
|
||||
{% end %}
|
||||
</label>
|
||||
|
||||
<label for="hints" class="form-check-label ml-4 mb-4">
|
||||
{% if data['user']['hints'] %}
|
||||
<input type="checkbox" class="form-check-input" id="hints" name="hints" checked=""
|
||||
value="1">Enable Hints?
|
||||
{% else %}
|
||||
<input type="checkbox" class="form-check-input" id="hints" name="hints" value="1"> Enable
|
||||
Hints?
|
||||
{% end %}
|
||||
</label>
|
||||
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-success mr-2"><i class="fas fa-save"></i> {{
|
||||
translate('panelConfig', 'save', data['lang']) }}</button>
|
||||
<button type="reset" onclick="location.href='/panel/panel_config'" class="btn btn-light"><i
|
||||
class="fas fa-undo-alt"></i> {{ translate('panelConfig', 'cancel', data['lang']) }}</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6 col-sm-12">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h4 class="card-title"><i class="fas fa-user-cog"></i> {{ translate('userConfig', 'configArea',
|
||||
data['lang']) }}</h4>
|
||||
<p class="card-description"> {{ translate('userConfig', 'configAreaDesc', data['lang']) }}</p>
|
||||
<blockquote class="blockquote">
|
||||
<p class="mb-0">
|
||||
{{ translate('userConfig', 'created', data['lang']) }} {{ str(data['user']['created']) }}
|
||||
<br />
|
||||
{{ translate('userConfig', 'lastLogin', data['lang']) }} {{ str(data['user']['last_login']) }}
|
||||
<br />
|
||||
{{ translate('userConfig', 'lastUpdate', data['lang']) }} {{ str(data['user']['last_update']) }}
|
||||
<br />
|
||||
{{ translate('userConfig', 'lastIP', data['lang']) }} {{ data['user']['last_ip'] }}
|
||||
<br />
|
||||
</p>
|
||||
</blockquote>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
{% if data['new_user'] %}
|
||||
<a class="btn btn-sm btn-danger disabled"><i class="fas fa-trash"></i>{{ translate('userConfig',
|
||||
'deleteUserB', data['lang']) }}</a><br />
|
||||
<small>{{ translate('userConfig', 'notExist', data['lang']) }}</small>
|
||||
{% elif data['user']['superuser'] %}
|
||||
<a class="btn btn-sm btn-danger disabled"><i class="fas fa-trash"></i> {{ translate('userConfig',
|
||||
'deleteUserB', data['lang']) }}</a><br />
|
||||
<small>{{ translate('userConfig', 'delSuper', data['lang']) }}</small>
|
||||
{% else %}
|
||||
<button class="btn btn-sm btn-danger delete-user"><i class="fas fa-trash"></i> {{
|
||||
translate('userConfig', 'deleteUserB', data['lang']) }}</a>
|
||||
{% end %}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -245,70 +297,70 @@
|
||||
<script>
|
||||
const userId = new URLSearchParams(document.location.search).get('id')
|
||||
|
||||
$( ".delete-user" ).click(function() {
|
||||
$(".delete-user").click(function () {
|
||||
var file_to_del = $(this).data("file");
|
||||
|
||||
console.log("User to delete is "+userId);
|
||||
console.log("User to delete is " + userId);
|
||||
|
||||
bootbox.confirm({
|
||||
title: "{% raw translate('userConfig', 'deleteUser', data['lang']) %} "+userId,
|
||||
message: "{{ translate('userConfig', 'confirmDelete', data['lang']) }}",
|
||||
buttons: {
|
||||
cancel: {
|
||||
label: '<i class="fas fa-times"></i> {{ translate("serverBackups", "cancel", data['lang']) }}'
|
||||
title: "{% raw translate('userConfig', 'deleteUser', data['lang']) %} " + userId,
|
||||
message: "{{ translate('userConfig', 'confirmDelete', data['lang']) }}",
|
||||
buttons: {
|
||||
cancel: {
|
||||
label: '<i class="fas fa-times"></i> {{ translate("serverBackups", "cancel", data['lang']) }}'
|
||||
},
|
||||
confirm: {
|
||||
className: 'btn-outline-danger',
|
||||
label: '<i class="fas fa-check"></i> {{ translate("serverBackups", "confirm", data['lang']) }}'
|
||||
}
|
||||
},
|
||||
callback: function (result) {
|
||||
console.log(result);
|
||||
if (result == true) {
|
||||
location.href="/panel/remove_user?id="+userId;
|
||||
confirm: {
|
||||
className: 'btn-outline-danger',
|
||||
label: '<i class="fas fa-check"></i> {{ translate("serverBackups", "confirm", data['lang']) }}'
|
||||
}
|
||||
},
|
||||
callback: function (result) {
|
||||
console.log(result);
|
||||
if (result === true) {
|
||||
location.href = "/panel/remove_user?id=" + userId;
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function superConfirm() {
|
||||
if (document.getElementById('superuser').checked){
|
||||
bootbox.confirm({
|
||||
title: "{{ translate('panelConfig', 'superConfirmTitle', data['lang']) }}",
|
||||
message: "{{ translate('panelConfig', 'superConfirm', data['lang']) }}",
|
||||
buttons: {
|
||||
if (document.getElementById('superuser').checked) {
|
||||
bootbox.confirm({
|
||||
title: "{{ translate('panelConfig', 'superConfirmTitle', data['lang']) }}",
|
||||
message: "{{ translate('panelConfig', 'superConfirm', data['lang']) }}",
|
||||
buttons: {
|
||||
cancel: {
|
||||
label: '<i class="fa fa-times"></i> {{ translate('panelConfig', 'cancel', data['lang']) }}'
|
||||
label: '<i class="fa fa-times"></i> {{ translate('panelConfig', 'cancel', data['lang']) }}'
|
||||
},
|
||||
confirm: {
|
||||
className: 'btn-outline-warning',
|
||||
label: '<i class="fa fa-check"></i> {{ translate('serverBackups', 'confirm', data['lang']) }}'
|
||||
label: '<i class="fa fa-check"></i> {{ translate('serverBackups', 'confirm', data['lang']) }}'
|
||||
}
|
||||
},
|
||||
callback: function (result) {
|
||||
if (result == true){
|
||||
},
|
||||
callback: function (result) {
|
||||
if (result === true) {
|
||||
return;
|
||||
}else{
|
||||
} else {
|
||||
document.getElementById('superuser').checked = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
}else{
|
||||
return
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//used to get cookies from browser - this is part of tornados xsrf protection - it's for extra security
|
||||
function getCookie(name) {
|
||||
var r = document.cookie.match("\\b" + name + "=([^;]*)\\b");
|
||||
return r ? r[1] : undefined;
|
||||
}
|
||||
//used to get cookies from browser - this is part of tornados xsrf protection - it's for extra security
|
||||
function getCookie(name) {
|
||||
var r = document.cookie.match("\\b" + name + "=([^;]*)\\b");
|
||||
return r ? r[1] : undefined;
|
||||
}
|
||||
|
||||
$( document ).ready(function() {
|
||||
console.log( "ready!" );
|
||||
$(document).ready(function () {
|
||||
console.log("ready!");
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
</script>
|
||||
|
@ -5,39 +5,60 @@
|
||||
<div class="row">
|
||||
<div class="col-sm-4 mr-2">
|
||||
{% if data['server_stats']['running'] %}
|
||||
<b>{{ translate('serverStats', 'serverStatus', data['lang']) }}:</b> <span id="status" class="text-success">{{ translate('serverStats', 'online', data['lang']) }}</span><br />
|
||||
<b>{{ translate('serverStats', 'serverStarted', data['lang']) }}:</b> <span id="started">{{ data['server_stats']['started'] }}</span><br />
|
||||
<b>{{ translate('serverStats', 'serverUptime', data['lang']) }}:</b> <span id="uptime">{{ translate('serverStats', 'errorCalculatingUptime', data['lang']) }}</span>
|
||||
<b>{{ translate('serverStats', 'serverStatus', data['lang']) }}:</b> <span id="status"
|
||||
class="text-success">{{ translate('serverStats', 'online', data['lang']) }}</span><br />
|
||||
<b>{{ translate('serverStats', 'serverStarted', data['lang']) }}:</b> <span id="started">{{
|
||||
data['server_stats']['started'] }}</span><br />
|
||||
<b>{{ translate('serverStats', 'serverUptime', data['lang']) }}:</b> <span id="uptime">{{
|
||||
translate('serverStats', 'errorCalculatingUptime', data['lang']) }}</span>
|
||||
{% elif data['server_stats']['crashed'] %}
|
||||
<b>{{ translate('serverStats', 'serverStatus', data['lang']) }}:</b> <span id="status" class="text-danger"> <i class="fas fa-exclamation-triangle"></i> {{ translate('dashboard', 'crashed', data['lang']) }}</span><br />
|
||||
<b>{{ translate('serverStats', 'serverStarted', data['lang']) }}:</b> <span id="started" class="text-danger"> <i class="fas fa-exclamation-triangle"></i> {{ translate('dashboard', 'crashed', data['lang']) }}</span><br />
|
||||
<b>{{ translate('serverStats', 'serverUptime', data['lang']) }}:</b> <span id="uptime" class="text-danger"> <i class="fas fa-exclamation-triangle"></i> {{ translate('dashboard', 'crashed', data['lang']) }}</span>
|
||||
<b>{{ translate('serverStats', 'serverStatus', data['lang']) }}:</b> <span id="status" class="text-danger">
|
||||
<i class="fas fa-exclamation-triangle"></i> {{ translate('dashboard', 'crashed', data['lang'])
|
||||
}}</span><br />
|
||||
<b>{{ translate('serverStats', 'serverStarted', data['lang']) }}:</b> <span id="started"
|
||||
class="text-danger"> <i class="fas fa-exclamation-triangle"></i> {{ translate('dashboard', 'crashed',
|
||||
data['lang']) }}</span><br />
|
||||
<b>{{ translate('serverStats', 'serverUptime', data['lang']) }}:</b> <span id="uptime" class="text-danger">
|
||||
<i class="fas fa-exclamation-triangle"></i> {{ translate('dashboard', 'crashed', data['lang']) }}</span>
|
||||
{% else %}
|
||||
<b>{{ translate('serverStats', 'serverStatus', data['lang']) }}:</b> <span id="status" class="text-warning">{{ translate('serverStats', 'offline', data['lang']) }}</span><br />
|
||||
<b>{{ translate('serverStats', 'serverStarted', data['lang']) }}:</b> <span id="started" class="text-warning">{{ translate('serverStats', 'offline', data['lang']) }}</span><br />
|
||||
<b>{{ translate('serverStats', 'serverUptime', data['lang']) }}:</b> <span id="uptime" class="text-warning">{{ translate('serverStats', 'offline', data['lang']) }}</span>
|
||||
<b>{{ translate('serverStats', 'serverStatus', data['lang']) }}:</b> <span id="status"
|
||||
class="text-warning">{{ translate('serverStats', 'offline', data['lang']) }}</span><br />
|
||||
<b>{{ translate('serverStats', 'serverStarted', data['lang']) }}:</b> <span id="started"
|
||||
class="text-warning">{{ translate('serverStats', 'offline', data['lang']) }}</span><br />
|
||||
<b>{{ translate('serverStats', 'serverUptime', data['lang']) }}:</b> <span id="uptime"
|
||||
class="text-warning">{{ translate('serverStats', 'offline', data['lang']) }}</span>
|
||||
{% end %}
|
||||
<br>
|
||||
<b>{{ translate('serverStats', 'serverTimeZone', data['lang']) }}:</b> <span class="text-info">{{ data['serverTZ'] }}</span>
|
||||
<b>{{ translate('serverStats', 'serverTimeZone', data['lang']) }}:</b> <span class="text-info">{{
|
||||
data['serverTZ'] }}</span>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-3 mr-2">
|
||||
<b>{{ translate('serverStats', 'cpuUsage', data['lang']) }}:</b> <span id="cpu">{{ data['server_stats']['cpu'] }}%</span> <br />
|
||||
<b>{{ translate('serverStats', 'memUsage', data['lang']) }}:</b> <span id="mem" >{{ data['server_stats']['mem'] }}</span> <br />
|
||||
<b>{{ translate('serverStats', 'cpuUsage', data['lang']) }}:</b> <span id="cpu">{{
|
||||
data['server_stats']['cpu'] }}%</span> <br />
|
||||
<b>{{ translate('serverStats', 'memUsage', data['lang']) }}:</b> <span id="mem">{{
|
||||
data['server_stats']['mem'] }}</span> <br />
|
||||
{% if data['server_stats']['int_ping_results'] %}
|
||||
<b>{{ translate('serverStats', 'players', data['lang']) }}:</b> <span id="players" >{{ data['server_stats']['online'] }} / {{ data['server_stats']['max'] }}</span><br />
|
||||
<b>{{ translate('serverStats', 'players', data['lang']) }}:</b> <span id="players">{{
|
||||
data['server_stats']['online'] }} / {{ data['server_stats']['max'] }}</span><br />
|
||||
{% else %}
|
||||
<b>{{ translate('serverStats', 'players', data['lang']) }}:</b> <span id="players" >0/0</span><br />
|
||||
<b>{{ translate('serverStats', 'players', data['lang']) }}:</b> <span id="players">0/0</span><br />
|
||||
{% end %}
|
||||
</div>
|
||||
|
||||
<div class="col-sm-3 mr-2">
|
||||
{% if data['server_stats']['version'] != 'False' %}
|
||||
<b>{{ translate('serverStats', 'version', data['lang']) }}:</b> <span id="version">{{ data['server_stats']['version'] }}</span><br />
|
||||
<b>{{ translate('serverStats', 'description', data['lang']) }}:</b> <span id="input_motd" style="max-width: 10px; max-height: 10px" class="input_motd">{{ data['server_stats']['desc'] }}</span> <br />
|
||||
<b>{{ translate('serverStats', 'version', data['lang']) }}:</b> <span id="version">{{
|
||||
data['server_stats']['version'] }}</span><br />
|
||||
<b>{{ translate('serverStats', 'description', data['lang']) }}:</b> <span id="input_motd"
|
||||
style="max-width: 10px; max-height: 10px" class="input_motd">{{ data['server_stats']['desc'] }}</span>
|
||||
<br />
|
||||
{% else %}
|
||||
<b>{{ translate('serverStats', 'version', data['lang']) }}:</b> <span id="version">{{ translate('serverStats', 'unableToConnect', data['lang']) }}</span> <br />
|
||||
<b>{{ translate('serverStats', 'description', data['lang']) }}:</b> <span style="max-width: 10px; max-height: 10px" id="input_motd" class="input_motd">{{ translate('serverStats', 'unableToConnect', data['lang']) }}</span> <br />
|
||||
<b>{{ translate('serverStats', 'version', data['lang']) }}:</b> <span id="version">{{
|
||||
translate('serverStats', 'unableToConnect', data['lang']) }}</span> <br />
|
||||
<b>{{ translate('serverStats', 'description', data['lang']) }}:</b> <span
|
||||
style="max-width: 10px; max-height: 10px" id="input_motd" class="input_motd">{{ translate('serverStats',
|
||||
'unableToConnect', data['lang']) }}</span> <br />
|
||||
{% end %}
|
||||
<b>Server Type: <span class="text-info">{{data['server_stats']['server_type']}}</span></b>
|
||||
|
||||
@ -64,6 +85,15 @@
|
||||
seconds: duration._data.seconds
|
||||
}
|
||||
|
||||
if (Math.round(duration._data.days)) {
|
||||
obj = {
|
||||
days: Math.round(duration._data.days),
|
||||
hours: Math.round(duration._data.hours -= duration._data.days * 24),
|
||||
minutes: duration._data.minutes,
|
||||
seconds: duration._data.seconds
|
||||
}
|
||||
}
|
||||
|
||||
output = Object.entries(obj)
|
||||
.map(([type, num]) => {
|
||||
// make them strings
|
||||
@ -135,9 +165,9 @@
|
||||
server_input_motd = document.getElementById('input_motd');
|
||||
|
||||
/* TODO Update each element */
|
||||
if (server.running){
|
||||
server_status.setAttribute("class", "text-success");
|
||||
server_status.innerHTML = `{{ translate('serverStats', 'online', data['lang']) }}`;
|
||||
if (server.running) {
|
||||
server_status.setAttribute("class", "text-success");
|
||||
server_status.innerHTML = `{{ translate('serverStats', 'online', data['lang']) }}`;
|
||||
|
||||
startedUTC = server.started;
|
||||
startedUTC = moment.utc(startedUTC, 'YYYY-MM-DD HH:mm:ss');
|
||||
@ -156,9 +186,8 @@
|
||||
uptimeLoop = setInterval(calculateUptime, 1000);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (server.crashed){
|
||||
else {
|
||||
if (server.crashed) {
|
||||
server_status.setAttribute("class", "text-danger");
|
||||
server_status.innerHTML = `<i class="fas fa-exclamation-triangle"></i> {{ translate('dashboard', 'crashed', data['lang']) }}`;
|
||||
server_started.setAttribute("class", "text-danger");
|
||||
@ -167,37 +196,33 @@
|
||||
uptimeLoop = null;
|
||||
server_uptime.setAttribute("class", "text-danger");
|
||||
server_uptime.innerHTML = `<i class="fas fa-exclamation-triangle"></i> {{ translate('dashboard', 'crashed', data['lang']) }}`;
|
||||
}else{
|
||||
server_status.setAttribute("class", "text-warning");
|
||||
server_status.innerHTML = `{{ translate('serverStats', 'offline', data['lang']) }}`;
|
||||
server_started.setAttribute("class", "text-warning");
|
||||
server_started.innerHTML = `{{ translate('serverStats', 'offline', data['lang']) }}`;
|
||||
clearInterval(uptimeLoop);
|
||||
uptimeLoop = null;
|
||||
server_uptime.setAttribute("class", "text-warning");
|
||||
server_uptime.innerHTML = `{{ translate('serverStats', 'offline', data['lang']) }}`;
|
||||
} else {
|
||||
server_status.setAttribute("class", "text-warning");
|
||||
server_status.innerHTML = `{{ translate('serverStats', 'offline', data['lang']) }}`;
|
||||
server_started.setAttribute("class", "text-warning");
|
||||
server_started.innerHTML = `{{ translate('serverStats', 'offline', data['lang']) }}`;
|
||||
clearInterval(uptimeLoop);
|
||||
uptimeLoop = null;
|
||||
server_uptime.setAttribute("class", "text-warning");
|
||||
server_uptime.innerHTML = `{{ translate('serverStats', 'offline', data['lang']) }}`;
|
||||
}
|
||||
}
|
||||
|
||||
server_cpu.innerHTML = server.cpu + ` %`;
|
||||
server_mem.innerHTML = server.mem;
|
||||
|
||||
if (server.int_ping_results)
|
||||
{
|
||||
if (server.int_ping_results) {
|
||||
server_players.innerHTML = server.online + `/` + server.max;
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
server_players.innerHTML = `0/0`;
|
||||
}
|
||||
|
||||
if (server.version)
|
||||
{
|
||||
if (server.version) {
|
||||
server_version.innerHTML = server.version;
|
||||
server_input_motd.innerHTML = server.desc;
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
server_version.innerHTML = `{{ translate('serverStats', 'unableToConnect', data['lang']) }}`;
|
||||
server_input_motd.innerHTML = `{{ translate('serverStats', 'unableToConnect', data['lang']) }}`;
|
||||
}
|
||||
@ -213,4 +238,4 @@
|
||||
webSocket.on('update_server_details', update_server_details);
|
||||
//}
|
||||
});
|
||||
</script>
|
||||
</script>
|
@ -111,7 +111,7 @@
|
||||
|
||||
{% block js %}
|
||||
<script>
|
||||
|
||||
const serverId = new URLSearchParams(document.location.search).get('id')
|
||||
|
||||
//used to get cookies from browser - this is part of tornados xsrf protection - it's for extra security
|
||||
function getCookie(name) {
|
||||
@ -145,7 +145,7 @@
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
headers: { 'X-XSRFToken': token },
|
||||
url: '/ajax/send_command?id=1',
|
||||
url: '/ajax/send_command?id=' + serverId,
|
||||
data: { command },
|
||||
success: function (data) {
|
||||
console.log("got response:");
|
||||
|
@ -306,6 +306,24 @@
|
||||
|
||||
|
||||
$(document).ready(function () {
|
||||
try {
|
||||
if ($('#backup_path').val() == '') {
|
||||
console.log('true')
|
||||
try {
|
||||
document.getElementById('backup_now_button').disabled = true;
|
||||
} catch {
|
||||
|
||||
}
|
||||
} else {
|
||||
document.getElementById('backup_now_button').disabled = false;
|
||||
}
|
||||
} catch {
|
||||
try {
|
||||
document.getElementById('backup_now_button').disabled = false;
|
||||
} catch {
|
||||
|
||||
}
|
||||
}
|
||||
console.log("ready!");
|
||||
$("#backup_config_box").hide();
|
||||
$("#backup_save_note").hide();
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -44,11 +44,18 @@
|
||||
<div class="card">
|
||||
<div class="card-header header-sm d-flex justify-content-between align-items-center">
|
||||
<h4 class="card-title"><i class="fas fa-calendar"></i> Scheduled Tasks</h4>
|
||||
<span class="too_small" title="{{ translate('serverSchedules', 'cannotSee', data['lang']) }}" , data-content="{{ translate('serverSchedules', 'cannotSeeOnMobile', data['lang']) }}" , data-placement="bottom"></span>
|
||||
<div><button onclick="location.href=`/panel/add_schedule?id={{ data['server_stats']['server_id']['server_id'] }}`" class="btn btn-info">Create New Schedule <i class="fas fa-pencil-alt"></i></button></div>
|
||||
{% 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>
|
||||
{% end %}
|
||||
<div><button
|
||||
onclick="location.href=`/panel/add_schedule?id={{ data['server_stats']['server_id']['server_id'] }}`"
|
||||
class="btn btn-info">Create New Schedule <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;">ID</th>
|
||||
|
File diff suppressed because it is too large
Load Diff
16
app/migrations/20210915205501_waiting_start_1 copy.py
Normal file
16
app/migrations/20210915205501_waiting_start_1 copy.py
Normal file
@ -0,0 +1,16 @@
|
||||
# Generated by database migrator
|
||||
import peewee
|
||||
|
||||
|
||||
def migrate(migrator, database, **kwargs):
|
||||
migrator.add_columns("users", hints=peewee.BooleanField(default=True))
|
||||
"""
|
||||
Write your migrations here.
|
||||
"""
|
||||
|
||||
|
||||
def rollback(migrator, database, **kwargs):
|
||||
migrator.drop_columns("users", ["hints"])
|
||||
"""
|
||||
Write your rollback migrations here.
|
||||
"""
|
42
app/migrations/stats/20220427_init.py
Normal file
42
app/migrations/stats/20220427_init.py
Normal file
@ -0,0 +1,42 @@
|
||||
import peewee
|
||||
import datetime
|
||||
|
||||
from app.classes.models.servers import Servers
|
||||
|
||||
|
||||
def migrate(migrator, database, **kwargs):
|
||||
db = database
|
||||
|
||||
class ServerStats(peewee.Model):
|
||||
stats_id = peewee.AutoField()
|
||||
created = peewee.DateTimeField(default=datetime.datetime.now)
|
||||
server_id = peewee.ForeignKeyField(Servers, backref="server", index=True)
|
||||
started = peewee.CharField(default="")
|
||||
running = peewee.BooleanField(default=False)
|
||||
cpu = peewee.FloatField(default=0)
|
||||
mem = peewee.FloatField(default=0)
|
||||
mem_percent = peewee.FloatField(default=0)
|
||||
world_name = peewee.CharField(default="")
|
||||
world_size = peewee.CharField(default="")
|
||||
server_port = peewee.IntegerField(default=25565)
|
||||
int_ping_results = peewee.CharField(default="")
|
||||
online = peewee.IntegerField(default=0)
|
||||
max = peewee.IntegerField(default=0)
|
||||
players = peewee.CharField(default="")
|
||||
desc = peewee.CharField(default="Unable to Connect")
|
||||
version = peewee.CharField(default="")
|
||||
updating = peewee.BooleanField(default=False)
|
||||
waiting_start = peewee.BooleanField(default=False)
|
||||
first_run = peewee.BooleanField(default=True)
|
||||
crashed = peewee.BooleanField(default=False)
|
||||
downloading = peewee.BooleanField(default=False)
|
||||
|
||||
class Meta:
|
||||
table_name = "server_stats"
|
||||
database = db
|
||||
|
||||
migrator.create_table(ServerStats)
|
||||
|
||||
|
||||
def rollback(migrator, database, **kwargs):
|
||||
migrator.drop_table("server_stats")
|
@ -176,7 +176,8 @@
|
||||
"not-downloaded": "We can't seem to find your executable file. Has it finished downloading? Are the permissions set to executable?",
|
||||
"portReminder": "We have detected this is the first time {} has been run. Make sure to forward port {} through your router/firewall to make this remotely accessible from the internet.",
|
||||
"start-error": "Server {} failed to start with error code: {}",
|
||||
"terribleFailure": "What a Terrible Failure!"
|
||||
"terribleFailure": "What a Terrible Failure!",
|
||||
"fileTooLarge": "Upload failed. File upload too large. Contact system administrator for assistance."
|
||||
},
|
||||
"footer": {
|
||||
"allRightsReserved": "All rights reserved",
|
||||
@ -516,7 +517,7 @@
|
||||
"notExist": "You cannot delete something that doesn't exist!",
|
||||
"pageTitle": "Edit User",
|
||||
"pageTitleNew": "Create User",
|
||||
"password": "Password",
|
||||
"password": "New Password",
|
||||
"permName": "Permission Name",
|
||||
"repeat": "Repeat Password",
|
||||
"roleName": "Role Name",
|
||||
|
532
app/translations/it_IT.json
Normal file
532
app/translations/it_IT.json
Normal file
@ -0,0 +1,532 @@
|
||||
{
|
||||
"404": {
|
||||
"contact": "Contatta il supporto di Crafty Control tramite Discord",
|
||||
"unableToFind": "Non siamo riusciti a trovare la pagina che cercavi. Per favore prova di nuovo, oppure torna indietro e riprova.",
|
||||
"notFound": "Pagina non trovata"
|
||||
},
|
||||
"accessDenied": {
|
||||
"accessDenied": "Accesso negato",
|
||||
"contact": "Contatta il supporto di Crafty Control tramite Discord",
|
||||
"contactAdmin": "Contatta l'amministratore del tuo server per l'accesso a questa risorsa, o se pensi tu debba aver accesso a questa risorsa, contatta il supporto tecnico.",
|
||||
"noAccess": "Non hai accesso a questa risorsa"
|
||||
},
|
||||
"apiKeys": {
|
||||
"apiKeys": "Chiavi API",
|
||||
"auth": "Autorizzato? ",
|
||||
"buttons": "Pulsanti",
|
||||
"config": "Configura",
|
||||
"crafty": "Crafty: ",
|
||||
"created": "Creato",
|
||||
"createNew": "Crea un nuovo Token API",
|
||||
"deleteKeyConfirmation": "Vuoi cancellare questa chiave API? Non puoi tornare indietro.",
|
||||
"deleteKeyConfirmationTitle": "Rimuovere la chiave API ${keyId}?",
|
||||
"getToken": "Prendi un Token",
|
||||
"name": "Nome",
|
||||
"nameDesc": "Come desideri chiamare questo Token API? ",
|
||||
"no": "No",
|
||||
"pageTitle": "Modifica le chiavi API degli utenti",
|
||||
"permName": "Nome Permesso",
|
||||
"perms": "Permessi",
|
||||
"server": "Server: ",
|
||||
"superUser": "Super User",
|
||||
"yes": "Sì"
|
||||
},
|
||||
"base": {
|
||||
"doesNotWorkWithoutJavascript": "<strong>Avviso: </strong>Crafty non funziona a dovere se JavaScript è disabilitato!"
|
||||
},
|
||||
"credits": {
|
||||
"developmentTeam": "Squadra di Svuluppo",
|
||||
"hugeDesc": "Un enorme",
|
||||
"pageDescription": "Senza queste persone, non avremmo Crafty",
|
||||
"pageTitle": "Crediti",
|
||||
"patreonDesc": "ai nostri supporter di Patreon!",
|
||||
"patreonLevel": "Livello",
|
||||
"patreonName": "Nome",
|
||||
"patreonOther": "Altro",
|
||||
"patreonSupporter": "Supporter Patreon",
|
||||
"patreonUpdate": "Ultimo aggiornamento:",
|
||||
"retiredStaff": "Staff ritirato",
|
||||
"supportTeam": "Squadra di supporto e documentazione",
|
||||
"thankYou": "GRAZIE",
|
||||
"translationDesc": "alla nostra community di traduttori!",
|
||||
"translationName": "Nome",
|
||||
"translationTitle": "Traduttore in lingua",
|
||||
"translator": "Traduttori"
|
||||
},
|
||||
"dashboard": {
|
||||
"dashboard": "Pannello di Controllo",
|
||||
"memUsage": "Utilizzo della memoria",
|
||||
"cpuUsage": "Utilizzo del Processore",
|
||||
"host": "Host",
|
||||
"players": "Giocatori",
|
||||
"backups": "Backups",
|
||||
"newServer": "Crea un Nuovo Server",
|
||||
"allServers": "Tutti i Server",
|
||||
"server": "Server",
|
||||
"actions": "Azioni",
|
||||
"size": "Dimensioni della Cartella del Server",
|
||||
"motd": "MOTD",
|
||||
"version": "Versione",
|
||||
"status": "Stato",
|
||||
"online": "Online",
|
||||
"offline": "Offline",
|
||||
"lastBackup": "Ultimo:",
|
||||
"nextBackup": "Prossimo:",
|
||||
"servers": "Servers",
|
||||
"cannotSeeOnMobile": "Non vedi nulla da mobile?",
|
||||
"cannotSee": "Non vedi qualcosa?",
|
||||
"cannotSeeOnMobile2": "Prova a scorrere la tabella orizzontalmente.",
|
||||
"max": "Massimo",
|
||||
"avg": "Media",
|
||||
"bePatientStart": "Per favore sii paziente mentre avviamo il server.<br /> Questa schermata si aggiornerà a breveThis screen will refresh in a moment",
|
||||
"bePatientStop": "Per favore sii paziente while we stop the server.<br /> Questa schermata si aggiornerà a breve",
|
||||
"bePatientRestart": "Per favore sii paziente mentre riavviamo il server.<br /> Questa schermata si aggiornerà a breve",
|
||||
"bePatientClone": "Per favore sii paziente mentre cloniamo il server.<br /> Questa schermata si aggiornerà a breve",
|
||||
"sendingCommand": "Invio il tuo comando",
|
||||
"cpuCurFreq": "Velocità attuale CPU",
|
||||
"cpuMaxFreq": "Velocità massima CPU",
|
||||
"cpuCores": "CPU Cores",
|
||||
"start": "Start",
|
||||
"stop": "Stop",
|
||||
"clone": "Clona",
|
||||
"kill": "Termina il Processo",
|
||||
"restart": "Riavvia",
|
||||
"killing": "Terminando il processo...",
|
||||
"starting": "Avvio ritardato",
|
||||
"delay-explained": "Il servizio/agente è stato avviato di recente e sta ritardando l'avvio del server di Minecraft",
|
||||
"no-servers": "Attualmente non ci sono server. Per cominciare, cliccalick",
|
||||
"welcome": "Benvenuto su Crafty Controller",
|
||||
"crashed": "Crashato"
|
||||
},
|
||||
"datatables": {
|
||||
"i18n": {
|
||||
"decimal": "",
|
||||
"emptyTable": "Nessun dato disponibile nella tabella",
|
||||
"info": "Mostro da _START_ a _END_ di _TOTAL_ record",
|
||||
"infoEmpty": "Mostro da 0 a 0 di 0 record",
|
||||
"infoFiltered": "(filtrato da _MAX_ record totali)",
|
||||
"infoPostFix": "",
|
||||
"thousands": ",",
|
||||
"lengthMenu": "Mostra _MENU_ record",
|
||||
"loadingRecords": "Carico...",
|
||||
"processing": "Calcolo...",
|
||||
"search": "Cerca:",
|
||||
"zeroRecords": "Nessun record corrispondente trovato",
|
||||
"paginate": {
|
||||
"first": "Prima",
|
||||
"last": "Ultima",
|
||||
"next": "Prossima",
|
||||
"previous": "Precedente"
|
||||
},
|
||||
"aria": {
|
||||
"sortAscending": ": attiva per ordinare le colonne in modo ascendente",
|
||||
"sortDescending": ": attiva per ordinare le colonne in modo discendente"
|
||||
},
|
||||
"buttons": {
|
||||
"collection": "Collection <span class='ui-button-icon-primary ui-icon ui-icon-triangle-1-s'\/>",
|
||||
"colvis": "Visibilità colonne",
|
||||
"colvisRestore": "Ripristina visibilità",
|
||||
"copy": "Copy",
|
||||
"copyKeys": "Premi ctrl or u2318 + C per copiare i dati della tabella negli appunti di sistema.<br><br>Per cancellare, clicca questo messaggio o premi esc.",
|
||||
"copySuccess": {
|
||||
"1": "Copiata 1 riga negli appunti",
|
||||
"_": "Copiate %d righe negli appunti"
|
||||
},
|
||||
"copyTitle": "Copia negli appunti di sistema",
|
||||
"csv": "CSV",
|
||||
"excel": "Excel",
|
||||
"pageLength": {
|
||||
"-1": "Mostra tutte le righe",
|
||||
"1": "Mostra 1 riga",
|
||||
"_": "Mostra %d righe"
|
||||
},
|
||||
"pdf": "PDF",
|
||||
"print": "Stampa"
|
||||
},
|
||||
"select": {
|
||||
"rows": {
|
||||
"0": "Clicca su una riga per selezionarla",
|
||||
"1": "%d riga selezionata",
|
||||
"_": "%d righe selezionate"
|
||||
},
|
||||
"cells": {
|
||||
"0": "Clicca su una cella per selezionarla",
|
||||
"1": "%d cella selezionata",
|
||||
"_": "%d celle selezionate"
|
||||
},
|
||||
"columns": {
|
||||
"0": "Clicca su una colonna per selezionarla",
|
||||
"1": "%d colonna selezionata",
|
||||
"_": "%d colonne selezionate"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"error": {
|
||||
"contact": "Contact Crafty Control Support via Discord",
|
||||
"embarassing": "Oh my, well, this is embarrassing.",
|
||||
"error": "Error!",
|
||||
"eulaAgree": "Do you agree?",
|
||||
"eulaMsg": "You must agree to the EULA. A copy of the Mojang EULA is linked under this message.",
|
||||
"eulaTitle": "Agree To EULA",
|
||||
"hereIsTheError": "Here is the error",
|
||||
"internet": "We have detected the machine running Crafty has no connection to the internet. Client connections to the server may be limited.",
|
||||
"no-file": "We can't seem to locate the requested file. Double check the path. Does Crafty have proper permissions?",
|
||||
"noJava": "Server {} failed to start with error code: We have detected Java is not installed. Please install java then start the server.",
|
||||
"not-downloaded": "We can't seem to find your executable file. Has it finished downloading? Are the permissions set to executable?",
|
||||
"portReminder": "We have detected this is the first time {} has been run. Make sure to forward port {} through your router/firewall to make this remotely accessible from the internet.",
|
||||
"start-error": "Server {} failed to start with error code: {}",
|
||||
"terribleFailure": "What a Terrible Failure!"
|
||||
},
|
||||
"footer": {
|
||||
"allRightsReserved": "Tutti i diritti Riservati",
|
||||
"copyright": "Copyright",
|
||||
"version": "Versione"
|
||||
},
|
||||
"login": {
|
||||
"forgotPassword": "Password dimenticata",
|
||||
"login": "Accedi",
|
||||
"password": "Password",
|
||||
"username": "Nome utente"
|
||||
},
|
||||
"notify": {
|
||||
"activityLog": "Registri di Attività",
|
||||
"backupComplete": "Il Backup per il server {} è stato completato correttamente",
|
||||
"backupStarted": "Il Backup per il server {} è cominciato",
|
||||
"downloadLogs": "Scaricare i registri di Supporto?",
|
||||
"finishedPreparing": "Abbiamo finito di preparare i tuoi registri di supporto.Per favore clicca Scarica per scaricarli",
|
||||
"logout": "Disconnessione",
|
||||
"preparingLogs": "Per favore aspetta mentre prepariamo i tuoi registri... Ti invieremo una notifica quando saranno pronti. Potrebbe volerci un po' per installazioni grosse.",
|
||||
"supportLogs": "Registri di supporto"
|
||||
},
|
||||
"panelConfig": {
|
||||
"adminControls": "Controllo admin",
|
||||
"allowedServers": "Server permessi",
|
||||
"assignedRoles": "Ruoli assegnati",
|
||||
"cancel": "Cancella",
|
||||
"clearComms": "Pulisci i comandi non eseguiti",
|
||||
"delete": "Elimina",
|
||||
"edit": "Modifica",
|
||||
"enabled": "Abilitato",
|
||||
"newRole": "Aggiungi nuovo ruolo",
|
||||
"newUser": "Aggiungi nuovo utente",
|
||||
"pageTitle": "Configurazioni del pannello",
|
||||
"role": "Ruolo",
|
||||
"roles": "Ruoli",
|
||||
"roleUsers": "Utenti del ruolo",
|
||||
"save": "Salva",
|
||||
"superConfirm": "Procedi solo se vuoi che questo utente abbia accesso a TUTTO (tutti gli utenti, server, impostazioni del pannello, ecc...). Può anche revocare i tuoi poteri da superuser.",
|
||||
"superConfirmTitle": "Abilitare lo superuser? Sei sicuro?",
|
||||
"user": "Utente",
|
||||
"users": "Utenti"
|
||||
},
|
||||
"rolesConfig": {
|
||||
"config": "Configura ruolo",
|
||||
"configDesc": "Qui è dove puoi modificare la configurazione del ruolo",
|
||||
"configUpdate": "Ultimo aggiornamento: ",
|
||||
"created": "Creato il: ",
|
||||
"delRole": "Elimina ruolo",
|
||||
"doesNotExist": "Non puoi eliminare qualcosa che ancora non esiste",
|
||||
"pageTitle": "Modifica ruolo",
|
||||
"pageTitleNew": "Nuovo ruolo",
|
||||
"permAccess": "Abilitato?",
|
||||
"permName": "Nome permesso",
|
||||
"permsServer": "Permessi che questo ruolo ha per questi specifici server",
|
||||
"roleConfigArea": "Area di configurazione del ruolo",
|
||||
"roleDesc": "Come vorresti chiamare questo ruolo?",
|
||||
"roleName": "Nome del ruolo: ",
|
||||
"rolePerms": "Permessi del ruolo",
|
||||
"roleServers": "Server abilitati",
|
||||
"roleTitle": "Impostazioni del ruolo",
|
||||
"roleUserName": "Nome Utente",
|
||||
"roleUsers": "Utenti con il ruolo: ",
|
||||
"serverAccess": "Abilitato?",
|
||||
"serverName": "Nome del Server",
|
||||
"serversDesc": "Server a cui questo ruolo è consentito l'accesso"
|
||||
},
|
||||
"serverBackups": {
|
||||
"backupAtMidnight": "Auto-backup a mezzanotte?",
|
||||
"backupNow": "Effettua il Backup Ora!",
|
||||
"backupTask": "Un'azione di backup è cominciata.",
|
||||
"cancel": "Cancella",
|
||||
"clickExclude": "Clicca per selezionare le esclusioni",
|
||||
"compress": "Comprimi backup",
|
||||
"confirm": "Conferma",
|
||||
"confirmDelete": "Vuoi eliminare questo backup? Non puoi tornare indietro.",
|
||||
"confirmRestore": "Sei sicuro di voler ripristinare qeusto backup? Tutti i file correnti verranno sovrascritti allo stato di backup e saranno irrecuperabili.",
|
||||
"currentBackups": "Backup attuali",
|
||||
"delete": "Elimina",
|
||||
"destroyBackup": "Distruggere il backup \" + file_to_del + \"?",
|
||||
"download": "Scarica",
|
||||
"excludedBackups": "Percorsi esclusi: ",
|
||||
"excludedChoose": "Scegli i percorsi che desideri escludere dai tuoi backups",
|
||||
"exclusionsTitle": "Fai un backup delle esclusioni",
|
||||
"maxBackups": "Backup massimi",
|
||||
"maxBackupsDesc": "Crafty non memorizzerà più di N backup, cancellando quelli più vecchi (inserisci 0 per mantenerli tutti)",
|
||||
"options": "Opzioni",
|
||||
"path": "Percorso",
|
||||
"restore": "Ripristina",
|
||||
"restoring": "Ripristinando il backup. Potrebber volerci un momento. Per favore sii paziente.",
|
||||
"save": "Salva",
|
||||
"size": "Dimensioni",
|
||||
"storageLocation": "Percorso di memorizzazione",
|
||||
"storageLocationDesc": "Dove vuoi memorizzare i backup?"
|
||||
},
|
||||
"serverConfig": {
|
||||
"bePatientDelete": "Per favore sii paziente mentre rimuoviamo il tuo server dal pannello di Crafty. Questa schermata si chiuderà in pochi istanti.",
|
||||
"bePatientDeleteFiles": "Per favore sii paziente mentre rimuoviamo il tuo server dal pannello di Crafty e cancelliamo tutti i files. Questa schermata si chiuderà in pochi istanti.",
|
||||
"bePatientUpdate": "Per favore sii paziente mentre aggiorniamo il server. I tempi di download possono variare dalla tua velocità di internet.<br /> Questa schermata si aggiornerà a breve",
|
||||
"cancel": "Cancella",
|
||||
"crashTime": "Crash Timeout",
|
||||
"crashTimeDesc": "Quanto dobbiamo aspettare per considerare il tuo server crashato per colpa di un timeout?",
|
||||
"deleteFilesQuestion": "Eliminare i file del server dalla macchina?",
|
||||
"deleteFilesQuestionMessage": "Vuoi che crafty cancelli tutti i file del server dalla macchina? <br><br><strong>Questo include i backup del server.</strong>",
|
||||
"deleteServer": "Eliminare il server",
|
||||
"deleteServerQuestion": "Eliminare il server?",
|
||||
"deleteServerQuestionMessage": "Sei sicuro di voler eliminare questo server? Dopo la conferma non puoi tornare indietro...",
|
||||
"exeUpdateURL": "URL di aggiornamento dell'eseguibile del server",
|
||||
"exeUpdateURLDesc": "URL di download diretto per gli aggiornamenti del server.",
|
||||
"noDelete": "No, torna indietro",
|
||||
"noDeleteFiles": "No, eliminalo dal pannello di controllo e basta",
|
||||
"removeOldLogsAfter": "Rimuovi i registri vecchi dopo",
|
||||
"removeOldLogsAfterDesc": "Di quanti giorni dovrà essere vecchio un registro per essere cancellato (inserendo 0 non verranno cancellati)",
|
||||
"save": "Salva",
|
||||
"sendingDelete": "Elimino il server",
|
||||
"sendingRequest": "Invio la tua richiesta...",
|
||||
"serverAutoStart": "Avvio automatico del server",
|
||||
"serverAutostartDelay": "Ritardo d'avvio automatico",
|
||||
"serverAutostartDelayDesc": "Ritardo in secondi per l'avvio automatico (se abilitato qui sotto)",
|
||||
"serverCrashDetection": "Rilevamento dei crash del Server",
|
||||
"serverExecutable": "Eseguibile del server",
|
||||
"serverExecutableDesc": "il file Eseguibile del server",
|
||||
"serverExecutionCommand": "Comando d'esecuzione del server",
|
||||
"serverExecutionCommandDesc": "Quello che verrà lanciato in un terminale nascosto",
|
||||
"serverIP": "IP del server",
|
||||
"serverIPDesc": "L'IP a cui Crafty si dovrà collegare per le statistiche (Prova un IP reale se 127.0.0.1 causa problemi)",
|
||||
"serverLogLocation": "Percorso dei Registri",
|
||||
"serverLogLocationDesc": "Percorso assoluto dei file di Registro",
|
||||
"serverName": "Nome del Server",
|
||||
"serverNameDesc": "Come desideri chiamare questo Server",
|
||||
"serverPath": "Cartella operativa del server",
|
||||
"serverPathDesc": "Percorso assoluto completo (non includere l'eseguibile)",
|
||||
"serverPort": "Porta del server",
|
||||
"serverPortDesc": "La Porta a cui Crafty si dovrà collegare per le statistiche",
|
||||
"serverStopCommand": "Comando d'arresto del server",
|
||||
"serverStopCommandDesc": "Comando inviato al server per l'arresto",
|
||||
"stopBeforeDeleting": "Per favore arresta il server prima di eliminarlo",
|
||||
"update": "Aggiorna l'eseguibile",
|
||||
"yesDelete": "Sì, elimina",
|
||||
"yesDeleteFiles": "Sì, elimina i files"
|
||||
},
|
||||
"serverConfigHelp": {
|
||||
"desc": "Qui è dove puoi cambiare la configurazione del tuo server",
|
||||
"perms": [
|
||||
"Raccomandiamo di <code>NON</code> cambiare il percorso di un server gestito da Crafty.",
|
||||
"Modificare il percorso <code>POTREBBE</code> rompere cose, specialmente su sistemi operativi Linux, dove i permessi dei file sono più stringenti.",
|
||||
"<br /><br/>",
|
||||
"Se senti di dover cambiare la posizione di un server, puoi farlo, ma dovrai dare all'utente \"crafty\" i permessi di leggere e scrivere nel nuovo percorso.",
|
||||
"<br />",
|
||||
"<br />",
|
||||
"Su Linux puoi farlo con questi comandi:<br />",
|
||||
"<code>",
|
||||
" sudo chown crafty:crafty /path/to/your/server -R<br />",
|
||||
" sudo chmod 2775 /path/to/your/server -R<br />",
|
||||
"</code>"
|
||||
],
|
||||
"title": "Area di configurazione del server"
|
||||
},
|
||||
"serverDetails": {
|
||||
"backup": "Backup",
|
||||
"config": "Configura",
|
||||
"files": "Files",
|
||||
"logs": "Registri",
|
||||
"playerControls": "Gestisci i giocatori",
|
||||
"schedule": "Programma",
|
||||
"serverDetails": "Dettagli del Server",
|
||||
"terminal": "Terminale"
|
||||
},
|
||||
"serverFiles": {
|
||||
"clickUpload": "Clicca qui per selezionare i file",
|
||||
"close": "Chiudi",
|
||||
"createDir": "Crea Cartella",
|
||||
"createDirQuestion": "Che nome vuoi dare alla nuova cartella?",
|
||||
"createFile": "Crea file",
|
||||
"createFileQuestion": "Che nome vuoi dare al nuovo file?",
|
||||
"default": "Default",
|
||||
"delete": "Elimina",
|
||||
"deleteItemQuestion": "Sei sicuro di voler eliminare \" + name + \"?",
|
||||
"deleteItemQuestionMessage": "Stai eliminando \\\"\" + path + \"\\\"!<br/><br/>Questa azione è irreversible e sarà perso per sempre!",
|
||||
"download": "Scarica",
|
||||
"editingFile": "Modificando i files",
|
||||
"error": "Si è verificato un errore nel recuperare i files",
|
||||
"fileReadError": "Errore nella lettura del file",
|
||||
"files": "Files",
|
||||
"keybindings": "Scorciatoie da tastiera",
|
||||
"loadingRecords": "Caricando i files...",
|
||||
"noDelete": "No",
|
||||
"noscript": "Il gestore file non funziona senza JavaScript",
|
||||
"rename": "Rinomina",
|
||||
"renameItemQuestion": "Quale sarà il nuovo nome?",
|
||||
"save": "Salva",
|
||||
"stayHere": "NON ABBANDONARE QUESTA PAGINA!",
|
||||
"unsupportedLanguage": "Avviso: Questo non è un tipo di file supportato",
|
||||
"unzip": "Scompatta",
|
||||
"upload": "Carica",
|
||||
"uploadTitle": "Carica i Files su: ",
|
||||
"waitUpload": "Per favore aspetta mentre carichiamo i tuoi files... Potrebbe volerci un momento.",
|
||||
"yesDelete": "Sì, conosco le conseguenze"
|
||||
},
|
||||
"serverPlayerManagement": {
|
||||
"bannedPlayers": "Giocatori Banditi",
|
||||
"loadingBannedPlayers": "Carico i giocatori banditi",
|
||||
"players": "Giocatori"
|
||||
},
|
||||
"serverScheduleConfig": {
|
||||
"backup": "Fai un Backup del Server",
|
||||
"basic": "Basic",
|
||||
"children": "Azioni figlie legate a questa: ",
|
||||
"command": "Comando",
|
||||
"command-explain": "Quale comando vuoi che eseguiamo? Non includere la '/'",
|
||||
"cron": "Cron",
|
||||
"cron-explain": "Inserisci la stringa CRON",
|
||||
"custom": "Comando personalizzato",
|
||||
"days": "Giorni",
|
||||
"enabled": "Abilitata",
|
||||
"hours": "Ore",
|
||||
"interval": "Intervallo",
|
||||
"interval-explain": "Ogni quanto vuoi che questa azione venga eseguita?",
|
||||
"minutes": "Minuti",
|
||||
"offset": "Offset di ritardo",
|
||||
"offset-explain": "Quanto dobbiamo aspettare prima di eseguire questo dopo aver eseguito la prima azione? (Secondi)",
|
||||
"one-time": "Elimina dopo l'esecuzione",
|
||||
"parent": "Seleziona un'azione programmata padre",
|
||||
"parent-explain": "Quale azione dovrebbe far eseguire questa?",
|
||||
"reaction": "Reazione",
|
||||
"restart": "Riavvia il Server",
|
||||
"start": "Avvia il server",
|
||||
"stop": "Arresta il Server",
|
||||
"time": "Orario",
|
||||
"time-explain": "A che ora vuoi eseguire la tua azione programmata?"
|
||||
},
|
||||
"serverSchedules": {
|
||||
"areYouSure": "Eliminare l'azione programmata?",
|
||||
"cancel": "Cancella",
|
||||
"cannotSee": "Non vedi tutto?",
|
||||
"cannotSeeOnMobile": "Prova a cliccare su un'azione programmata per tutti i dettagli.",
|
||||
"confirm": "Conferma",
|
||||
"confirmDelete": "Vuoi eliminare l'azione programmata? Non puoi tornare indietro."
|
||||
},
|
||||
"serverStats": {
|
||||
"cpuUsage": "Utilizzo del Processore",
|
||||
"description": "Descrizione",
|
||||
"errorCalculatingUptime": "Errore nel calcolo dei tempi di operazione",
|
||||
"memUsage": "Utilizzo della memoria",
|
||||
"offline": "Offline",
|
||||
"online": "Online",
|
||||
"players": "Giocatori",
|
||||
"serverStarted": "Server Avviato",
|
||||
"serverStatus": "Stato del Server",
|
||||
"serverTime": "UTC Time",
|
||||
"serverTimeZone": "Timezone del Server",
|
||||
"serverUptime": "Tempo di operazione del Server",
|
||||
"starting": "Avvio ritardato",
|
||||
"unableToConnect": "Impossibile connettersi",
|
||||
"version": "Versione"
|
||||
},
|
||||
"serverTerm": {
|
||||
"commandInput": "Inserisci il comando",
|
||||
"delay-explained": "Il servizio/agente è stato avviato di recente e sta ritardando l'avvio del server di Minecraft",
|
||||
"downloading": "Scaricando...",
|
||||
"restart": "Riavvia",
|
||||
"sendCommand": "Invia il comando",
|
||||
"start": "Avvia",
|
||||
"starting": "Avvio ritardato",
|
||||
"stop": "Ferma",
|
||||
"stopScroll": "Ferma lo scorrimento automatico",
|
||||
"updating": "Aggiornando..."
|
||||
},
|
||||
"serverWizard": {
|
||||
"absoluteServerPath": "Percorso Assoluto al tuo Server",
|
||||
"absoluteZipPath": "Percorso Assoluto del Server",
|
||||
"addRole": "Aggiungi il Server a Ruoli Esistenti",
|
||||
"autoCreate": "Se non sono selezionati, Crafty ne creerà per te!",
|
||||
"bePatient": "Per favore attendi mentre ' + (importing ? 'importiamo' : 'scarichiamo') + ' il Server",
|
||||
"buildServer": "Compila il Server!",
|
||||
"clickRoot": "Clicca qui per selezionare la Directory Radice",
|
||||
"close": "Chiudi",
|
||||
"defaultPort": "25565 default",
|
||||
"downloading": "Scaricando il Server...",
|
||||
"explainRoot": "Per favore clicca il pulsante qui sotto per selezionare la cartella radice del server all'interno dell'archivio",
|
||||
"importing": "Importando il Server...",
|
||||
"importServer": "Importa un Server Esistente",
|
||||
"importServerButton": "Importa Server!",
|
||||
"importZip": "Importa da un File Zip",
|
||||
"maxMem": "Memoria Massima",
|
||||
"minMem": "Memoria minima",
|
||||
"myNewServer": "Il mio nuovo Server",
|
||||
"newServer": "Crea un Nuovo Server",
|
||||
"quickSettings": "Impostazioni Rapide",
|
||||
"quickSettingsDescription": "Non ti preoccupare, puoi cambiarle più tardi",
|
||||
"resetForm": "Reset Form",
|
||||
"save": "Salva",
|
||||
"selectRole": "Seleziona i Ruoli",
|
||||
"selectRoot": "Seleziona la directory radice dell'archivio",
|
||||
"selectType": "Seleziona un Tipo",
|
||||
"selectVersion": "Seleziona una versione",
|
||||
"selectZipDir": "Seleziona il percorso in memoria in cui scompatteremo i file",
|
||||
"serverJar": "File eseguibile del Server",
|
||||
"serverName": "Nome Server",
|
||||
"serverPath": "Percorso del Server",
|
||||
"serverPort": "Porta del Server",
|
||||
"serverType": "Tipo di Server",
|
||||
"serverVersion": "Versione del Server",
|
||||
"sizeInGB": "Dimensione in GB",
|
||||
"zipPath": "Percorso del Server"
|
||||
},
|
||||
"sidebar": {
|
||||
"contribute": "Contribuisci",
|
||||
"credits": "Crediti",
|
||||
"dashboard": "Pannello di controllo",
|
||||
"documentation": "Documentazione",
|
||||
"navigation": "Navigazione",
|
||||
"newServer": "Crea un Nuovo Server",
|
||||
"servers": "Servers"
|
||||
},
|
||||
"userConfig": {
|
||||
"apiKey": "Chiavi API",
|
||||
"auth": "Autorizzato? ",
|
||||
"config": "Configura",
|
||||
"configArea": "Area di configurazione utente",
|
||||
"configAreaDesc": "Qui è dove modifichi tutte le impostazioni utente",
|
||||
"confirmDelete": "Sei sicuro di voler eliminare qeusto utente? Quest'azione è irreversibile.",
|
||||
"craftyPermDesc": "I permessi Crafty che questo utente possiede ",
|
||||
"craftyPerms": "Permessi di Crafty: ",
|
||||
"created": "Creato il: ",
|
||||
"deleteUser": "Elimina Utente: ",
|
||||
"deleteUserB": "Elimina Utente",
|
||||
"delSuper": "Non puoi eliminare uno superuser",
|
||||
"enabled": "Abilitato",
|
||||
"gravDesc": "Questa email è solamente per l'uso di Gravatar™. Crafty non userà l'email in alcuna circostanza, se non per associare il Gravatar™",
|
||||
"gravEmail": "Gravatar™ Email",
|
||||
"lastIP": "Ultimo indirizzo IP: ",
|
||||
"lastLogin": "Ultimo accesso: ",
|
||||
"lastUpdate": "Ultimo aggiornamento: ",
|
||||
"leaveBlank": "Per modificare l'utente senza cambiare la passowrd, lascia il campo in bianco.",
|
||||
"member": "È membro?",
|
||||
"notExist": "Non puoi eliminare qualcosa che non esiste!",
|
||||
"pageTitle": "Modifica Utente",
|
||||
"pageTitleNew": "Crea Utente",
|
||||
"password": "Password",
|
||||
"permName": "Nome del Permesso",
|
||||
"repeat": "Ripeti la Password",
|
||||
"roleName": "Nome del ruolo",
|
||||
"super": "Super User",
|
||||
"userLang": "Linguaggio dell'utente",
|
||||
"userName": "Nome utente",
|
||||
"userNameDesc": "Come vuoi chiamare questo utente?",
|
||||
"userRoles": "Ruoli dell'utente",
|
||||
"userRolesDesc": "Ruoli di cui l'utente fa parte.",
|
||||
"userSettings": "Impostazioni Utente",
|
||||
"uses": "Numero di usi permessi (-1==Nessun limite)"
|
||||
}
|
||||
}
|
@ -1,347 +0,0 @@
|
||||
{
|
||||
"404": {
|
||||
"contact": "Contatta l'assistenza di Crafty Controller su Discord!",
|
||||
"notFound": "Pagina non trovata",
|
||||
"unableToFind": "We were unable to find the page you are looking for. Please try again, or go back and refresh."
|
||||
},
|
||||
"accessDenied": {
|
||||
"accessDenied": "Accesso negato",
|
||||
"contact": "Contatta il supporto di Crafty Control tramite Discord",
|
||||
"contactAdmin": "Contatta l'amministratore del tuo server per accedere a questa risorsa, o, se pensi tu debba avere accesso a tale risorsa, contatta il supporto.",
|
||||
"noAccess": "Non hai accesso a questa risorsa"
|
||||
},
|
||||
"base": {
|
||||
"doesNotWorkWithoutJavascript": "<strong>Warning: </strong>Crafty doesn't work properly when JavaScript isn't enabled!"
|
||||
},
|
||||
"dashboard": {
|
||||
"actions": "Azioni",
|
||||
"allServers": "Tutti i Servers",
|
||||
"avg": "Media",
|
||||
"backups": "Backups",
|
||||
"bePatientClone": "Per favore sii paziente mentre cloniamo il server.<br /> Questa schermata si aggiornerà in un momento",
|
||||
"bePatientRestart": "Per favore sii paziente mentre riavviamo il server.<br /> Questa schermata si aggiornerà in un momento",
|
||||
"bePatientStart": "Per favore sii paziente mentre accendiamo il server.<br /> Questa schermata si aggiornerà in un momento",
|
||||
"bePatientStop": "Per favore sii paziente mentre spegniamo il server.<br /> Questa schermata si aggiornerà in un momento",
|
||||
"cannotSee": "Non vedi nulla?",
|
||||
"cannotSeeOnMobile": "Non vedi nulla da mobile?",
|
||||
"cannotSeeOnMobile2": "Prova a scorrere sulla tabella lateralmente.",
|
||||
"clone": "Clona",
|
||||
"cpuCores": "Core della CPU",
|
||||
"cpuCurFreq": "Frequenza Attuale della CPU",
|
||||
"cpuMaxFreq": "Frequenza Massima della CPU",
|
||||
"cpuUsage": "Uso della CPU",
|
||||
"dashboard": "Dashboard",
|
||||
"delay-explained": "Il servizio è partito di recente e sta ritardando l'avvio dell'istanza del Server di Minecraft",
|
||||
"host": "Host",
|
||||
"kill": "Termina il processo",
|
||||
"killing": "Terminando il processo...",
|
||||
"lastBackup": "Ultimo:",
|
||||
"max": "Massimo",
|
||||
"memUsage": "Uso della Memoria",
|
||||
"motd": "Slogan",
|
||||
"newServer": "Crea un nuovo Server",
|
||||
"nextBackup": "Prossimo:",
|
||||
"no-servers": "Attualmente non ci sono server. Per cominciare, clicca",
|
||||
"offline": "Offline",
|
||||
"online": "Online",
|
||||
"players": "Giocatori",
|
||||
"restart": "Riavvia",
|
||||
"sendingCommand": "Inviando il tuo comando",
|
||||
"server": "Server",
|
||||
"servers": "Server",
|
||||
"start": "Avvia",
|
||||
"starting": "Avvio ritardato",
|
||||
"status": "Stato",
|
||||
"stop": "Ferma",
|
||||
"version": "Versione",
|
||||
"welcome": "Benvenuto su Crafty Controller",
|
||||
"world": "Mondo"
|
||||
},
|
||||
"datatables": {
|
||||
"i18n": {
|
||||
"aria": {
|
||||
"sortAscending": ": attiva per ordinare le colonne in modo ascendente",
|
||||
"sortDescending": ": attiva per ordinare le colonne in modo discendente"
|
||||
},
|
||||
"buttons": {
|
||||
"collection": "Collezione <span class='ui-button-icon-primary ui-icon ui-icon-triangle-1-s'/>",
|
||||
"colvis": "Visibilità della colonna",
|
||||
"colvisRestore": "Ripristina Visibilità",
|
||||
"copy": "Copia",
|
||||
"copyKeys": "Premi Ctrl o u2318 + C per copiare i dati della tabella negli appunti di sistema.<br><br> Per cancellare, clicca questo messaggio o premi ESC.",
|
||||
"copySuccess": {
|
||||
"1": "Copiata 1 riga negli appunti",
|
||||
"_": "Copiate %d righe negli appunti"
|
||||
},
|
||||
"copyTitle": "Copia negli appunti",
|
||||
"csv": "CSV",
|
||||
"excel": "Excel",
|
||||
"pageLength": {
|
||||
"1": "Mostra 1 riga",
|
||||
"-1": "Mostra tutte le righe",
|
||||
"_": "Mostra %d righe"
|
||||
},
|
||||
"pdf": "PDF",
|
||||
"print": "Print"
|
||||
},
|
||||
"decimal": "",
|
||||
"emptyTable": "Nessun dato disponibile nella tabella",
|
||||
"info": "Visualizzando da _START_ fino a _END_ di _TOTAL_ voci",
|
||||
"infoEmpty": "Visualizzando da 0 fino a 0 di 0 voci",
|
||||
"infoFiltered": "(Filtrato da_MAX_ voci totali)",
|
||||
"infoPostFix": "",
|
||||
"lengthMenu": "Mostra le voci di _MENU_ ",
|
||||
"loadingRecords": "Caricamento...",
|
||||
"paginate": {
|
||||
"first": "Primo",
|
||||
"last": "Ultimo",
|
||||
"next": "Prossima",
|
||||
"previous": "Precedente"
|
||||
},
|
||||
"processing": "Caricamento...",
|
||||
"search": "Cerca:",
|
||||
"select": {
|
||||
"cells": {
|
||||
"0": "Click on a cel to select it",
|
||||
"1": "%d cell selected",
|
||||
"_": "%d cells selected"
|
||||
},
|
||||
"columns": {
|
||||
"0": "Click on a column to select it",
|
||||
"1": "%d column selected",
|
||||
"_": "%d columns selected"
|
||||
},
|
||||
"rows": {
|
||||
"0": "Click on a row to select it",
|
||||
"1": "%d row selected",
|
||||
"_": "%d rows selected"
|
||||
}
|
||||
},
|
||||
"thousands": ",",
|
||||
"zeroRecords": "Nessuna voce corrispondente trovata"
|
||||
}
|
||||
},
|
||||
"error": {
|
||||
"closedPort": "Ci siamo accorti che la porta {} potrebbe non essere aperta, o un firewall potrebbe tenerla chiusa. Le connessioni remote al server potrebbero essere limitate.",
|
||||
"contact": "Contatta l'assistenza di Crafty Controller su Discord!",
|
||||
"embarassing": "Oh mamma, beh, questo è imbarazzante.",
|
||||
"error": "Errore!",
|
||||
"eulaAgree": "Accetti l'EULA?",
|
||||
"eulaMsg": "Devi accettare l'EULA. Una copia dell'EULA di Mojang è allegata sotto questo messaggio.",
|
||||
"eulaTitle": "Accetta il Contratto con l'Utente Finale",
|
||||
"hereIsTheError": "Ecco l'errore",
|
||||
"internet": "Ci siamo accorti che il server che fa girare Crafty non ha connessione a internet. Le connessioni dei Client potrebbero essere limitate.",
|
||||
"start-error": "Il server {} non è partito, con codice errore: {}",
|
||||
"terribleFailure": "Che crash epico!"
|
||||
},
|
||||
"footer": {
|
||||
"allRightsReserved": "Tutti i diritti riservati",
|
||||
"copyright": "Copyright",
|
||||
"version": "Versione"
|
||||
},
|
||||
"login": {
|
||||
"forgotPassword": "Password dimenticata",
|
||||
"login": "Log In",
|
||||
"password": "Password",
|
||||
"username": "Nome utente"
|
||||
},
|
||||
"panelConfig": {
|
||||
"cancel": "Cancella",
|
||||
"delete": "Elimina",
|
||||
"save": "Salva"
|
||||
},
|
||||
"serverBackups": {
|
||||
"backupAtMidnight": "Backup automatico a mezzanotte?",
|
||||
"backupNow": "Fai un Backup ora!",
|
||||
"backupTask": "È cominciato un processo di backup.",
|
||||
"cancel": "Cancella",
|
||||
"confirm": "Conferma",
|
||||
"confirmDelete": "Vuoi cancellare questo Backup? Questa azione non è annullabile.",
|
||||
"currentBackups": "Backup attuali",
|
||||
"delete": "Cancella",
|
||||
"destroyBackup": "Cancellare backup \" + file_to_del + \"?",
|
||||
"download": "Download",
|
||||
"maxBackups": "Backup massimi",
|
||||
"maxBackupsDesc": "Crafty non immagazzinerà più di N backup, cancellerà quelli più vecchi (inserisci 0 per mantenerli tutti)",
|
||||
"options": "Opzioni",
|
||||
"path": "Percorso",
|
||||
"save": "Salva",
|
||||
"size": "Dimensione",
|
||||
"storageLocation": "Percorso del backup",
|
||||
"storageLocationDesc": "Dove vuoi memorizzare i backup?"
|
||||
},
|
||||
"serverConfig": {
|
||||
"bePatientDelete": "Per favore sii paziente mentre rimuoviamo il server dal pannello. Questa schermata si aggiornerà in un momento.",
|
||||
"bePatientDeleteFiles": "Per favore sii paziente mentre rimuoviamo il server dal pannello ed eliminiamo i file. Questa schermata sparirà in un momento.",
|
||||
"bePatientUpdate": "Per favore sii paziente mentre aggiorniamo il server. I tempi di scaricamento possono variare in base alla tua velocità di Internet.<br /> Questa schermata si aggiornerà in un momento.",
|
||||
"cancel": "Cancella",
|
||||
"deleteFilesQuestion": "Eliminare i file del Server dalla macchina?",
|
||||
"deleteFilesQuestionMessage": "Vorresti che Crafty eliminasse tutti i file del Server dalla macchina Host?",
|
||||
"deleteServer": "Elimina Server",
|
||||
"deleteServerQuestion": "Eliminare il Server?",
|
||||
"deleteServerQuestionMessage": "Sei sicuro di voler eliminare questo server? Dopo la conferma non si può tornare indietro...",
|
||||
"exeUpdateURL": "URL per gli aggiornamenti dell'Eseguibile del Server",
|
||||
"exeUpdateURLDesc": "URL Diretto per il download di aggiornamenti.",
|
||||
"noDelete": "No, torna indietro",
|
||||
"noDeleteFiles": "No, rimuovili dal pannello e basta",
|
||||
"removeOldLogsAfter": "Rimuovi log più vecchi di ",
|
||||
"removeOldLogsAfterDesc": "Di quanti giorni dovrebbe essere vecchio un log per essere cancellato (0 per non cancellarne)",
|
||||
"save": "Salva",
|
||||
"sendingDelete": "Eliminando il Server",
|
||||
"sendingRequest": "Invio la tua richiesta...",
|
||||
"serverAutoStart": "Avvio automatico del Server",
|
||||
"serverAutostartDelay": "Ritardo Automatico dell'Avvio",
|
||||
"serverAutostartDelayDesc": "Il ritardo per far partire il server (Se abilitato più sotto)",
|
||||
"serverCrashDetection": "Rilevamento dei Crash del Server",
|
||||
"serverExecutable": "Eseguibile del Server",
|
||||
"serverExecutableDesc": "Il file Eseguibile del server",
|
||||
"serverExecutionCommand": "Comando di Esecuzione del Server",
|
||||
"serverExecutionCommandDesc": "Quello che verrà eseguito in un terminale nascosto",
|
||||
"serverIP": "Server IP",
|
||||
"serverIPDesc": "L'IP a cui Crafty dovrebbe connettersi per le statistiche (Prova un IP reale piuttosto di 127.0.0.1 se hai qualche problema)",
|
||||
"serverLogLocation": "Posizione del Log del Server",
|
||||
"serverLogLocationDesc": "Percorso Assoluto per Intero del File di Log",
|
||||
"serverName": "Nome del Server",
|
||||
"serverNameDesc": "Come vorresti chiamare questo server",
|
||||
"serverPath": "Cartella di Operazioni del Server",
|
||||
"serverPathDesc": "Percorso Assoluto per Intero (Escludendo l'eseguibile)",
|
||||
"serverPort": "Porta del Server",
|
||||
"serverPortDesc": "La Porta a cui Crafty dovrebbe connettersi per le statistiche",
|
||||
"serverStopCommand": "Comando per terminare il server",
|
||||
"serverStopCommandDesc": "Comando da inviare al server per fermarlo",
|
||||
"stopBeforeDeleting": "Per favore ferma il Server prima di eliminarlo",
|
||||
"update": "Aggiorna l'Eseguibile",
|
||||
"yesDelete": "Sì, eliminalo",
|
||||
"yesDeleteFiles": "Sì, cancella i file"
|
||||
},
|
||||
"serverConfigHelp": {
|
||||
"desc": "Qui è dove puoi cambiare la configurazione del tuo Server",
|
||||
"perms": [
|
||||
"È raccomandabile <code>NON</code> cambiare i percorsi di un Server gestito da Crafty.",
|
||||
"Cambiare i percorsi <code>PUO'</code> rompere cose, specialmente su sistemi tipo Linux dove i permessi dei file sono più restrittivi.",
|
||||
"<br /><br/>",
|
||||
"Se credi di dover cambiare il percorso di un server puoi farlo, a patto di dare all'utente \"crafty\" i permessi di leggere e scrivere nel percorso del server.",
|
||||
"<br />",
|
||||
"<br />",
|
||||
"Su Linux questa operazione si esegue con questi comandi:<br />",
|
||||
"<code>",
|
||||
" sudo chown crafty:crafty /percorso/al/tuo/server -R<br />",
|
||||
" sudo chmod 2775 /percorso/al/tuo/server -R<br />",
|
||||
"</code>"
|
||||
],
|
||||
"title": "Area di Configurazione del Server"
|
||||
},
|
||||
"serverDetails": {
|
||||
"backup": "Backup",
|
||||
"config": "Config",
|
||||
"files": "Files",
|
||||
"logs": "Logs",
|
||||
"playerControls": "Player Management",
|
||||
"schedule": "Pianifica",
|
||||
"serverDetails": "Dettagli del Server",
|
||||
"terminal": "Terminale"
|
||||
},
|
||||
"serverFiles": {
|
||||
"clickUpload": "Clicca qui per selezionare i tuoi file",
|
||||
"close": "Chiudi",
|
||||
"createDir": "Crea Cartella",
|
||||
"createDirQuestion": "Che nome vuoi dare alla nuova cartella?",
|
||||
"createFile": "Crea file",
|
||||
"createFileQuestion": "Che nome vuoi dare al nuovo file?",
|
||||
"default": "Default",
|
||||
"delete": "Cancella",
|
||||
"deleteItemQuestion": "Sei sicuro di voler eliminare \" + name + \"?",
|
||||
"deleteItemQuestionMessage": "Stai eliminando \\\"\" + path + \"\\\"!<br/><br/>Questa azione è irreversibile e non potrai tornare indietro!",
|
||||
"download": "Scarica",
|
||||
"editingFile": "Modificare file",
|
||||
"error": "Errore nel recuperare files",
|
||||
"fileReadError": "Errore nel leggere i file",
|
||||
"files": "Files",
|
||||
"keybindings": "Combinazioni di tasti",
|
||||
"noDelete": "No",
|
||||
"noscript": "Il File Manager non funziona senza JavaScript",
|
||||
"rename": "Rinomina",
|
||||
"renameItemQuestion": "Qual è il nuovo nome?",
|
||||
"save": "Salva",
|
||||
"stayHere": "NON ABBANDONARE QUESTA PAGINA!",
|
||||
"unsupportedLanguage": "Attenzione: Questo non è un tipo di file supportato",
|
||||
"unzip": "Estrai",
|
||||
"upload": "Carica",
|
||||
"uploadTitle": "Carica i file: ",
|
||||
"waitUpload": "Per favore attendi mentre carichiamo i tuoi file... Potrebbe volerci un po' di tempo.",
|
||||
"yesDelete": "Sì, capisco le conseguenze"
|
||||
},
|
||||
"serverPlayerManagement": {
|
||||
"bannedPlayers": "Giocatori Bannati",
|
||||
"loadingBannedPlayers": "Carico i Giocatori Bannati",
|
||||
"players": "Giocatori"
|
||||
},
|
||||
"serverStats": {
|
||||
"cpuUsage": "Utilizzo della CPU",
|
||||
"description": "Descrizione",
|
||||
"errorCalculatingUptime": "Errore nel calcolare il periodo di esecuzione del server",
|
||||
"memUsage": "Utilizzo della Memoria",
|
||||
"offline": "Offline",
|
||||
"online": "Online",
|
||||
"players": "Giocatori",
|
||||
"serverStarted": "Server Avviato",
|
||||
"serverStatus": "Stato del server",
|
||||
"serverTime": "Zona UTC",
|
||||
"serverUptime": "Tempo di esecuzione",
|
||||
"starting": "Avvio ritardato",
|
||||
"unableToConnect": "Non riesco a connettermi",
|
||||
"version": "Versione"
|
||||
},
|
||||
"serverTerm": {
|
||||
"commandInput": "Inserisci il tuo comando",
|
||||
"delay-explained": "Il servizio è partito di recente e sta ritardando l'avvio dell'istanza del Server di Minecraft",
|
||||
"restart": "Riavvia",
|
||||
"sendCommand": "Invia il comando",
|
||||
"start": "Avvia",
|
||||
"starting": "Avvio ritardato",
|
||||
"stop": "Ferma",
|
||||
"stopScroll": "Ferma lo scorrimento automatico",
|
||||
"updating": "Aggiornando..."
|
||||
},
|
||||
"serverWizard": {
|
||||
"absoluteServerPath": "Percorso assoluto del server",
|
||||
"absoluteZipPath": "Percorso assoluto del tuo Server in Zip",
|
||||
"addRole": "Aggiungi il Server a Ruoli Esistenti",
|
||||
"autoCreate": "Se non sono selezionati, Crafty ne creerà uno!",
|
||||
"bePatient": "Per favore sii paziente mentre ' + (importing ? 'importiamo' : 'scarichiamo') + ' il server",
|
||||
"buildServer": "Costruisci il Server!",
|
||||
"defaultPort": "25565 default",
|
||||
"downloading": "Scaricando il Server...",
|
||||
"importing": "Importando il Server...",
|
||||
"importServer": "Importa un Server esistente",
|
||||
"importServerButton": "Importa Server!",
|
||||
"importZip": "Importa da un file Zip",
|
||||
"maxMem": "Memoria Massima",
|
||||
"minMem": "Memoria Minima",
|
||||
"myNewServer": "Il mio nuovo server",
|
||||
"newServer": "Crea un nuovo Server",
|
||||
"quickSettings": "Impostazioni rapide",
|
||||
"quickSettingsDescription": "Non preoccuparti, puoi cambiare queste impostazioni in seguito",
|
||||
"resetForm": "Ripulisci il form",
|
||||
"selectRole": "Seleziona il o i ruoli",
|
||||
"selectType": "Seleziona un tipo",
|
||||
"selectVersion": "Seleziona un Server",
|
||||
"serverJar": "JarFile del server",
|
||||
"serverName": "Nome Server",
|
||||
"serverPath": "Percorso del Server",
|
||||
"serverPort": "Porta del Server",
|
||||
"serverType": "Tipo di Server",
|
||||
"serverVersion": "Versione Server",
|
||||
"sizeInGB": "Dimensione in GB",
|
||||
"zipPath": "Percorso Server"
|
||||
},
|
||||
"sidebar": {
|
||||
"contribute": "Contribuisci",
|
||||
"credits": "Crediti",
|
||||
"dashboard": "Dashboard",
|
||||
"documentation": "Documentazione",
|
||||
"navigation": "Navigazione",
|
||||
"newServer": "Crea un nuovo Server",
|
||||
"servers": "Servers"
|
||||
}
|
||||
}
|
44
config_examples/apache2.conf.example
Executable file
44
config_examples/apache2.conf.example
Executable file
@ -0,0 +1,44 @@
|
||||
#Base config made by Justman10000 and Zedifus (https://gitlab.com/Zedifus)
|
||||
#Adapted for WSS by Andrew McManus https://gitlab.com/amcmanu3
|
||||
#For this config you need to add the following mods
|
||||
#mod_ssl
|
||||
#mod_rewrite
|
||||
#mod_http_upgrade
|
||||
#mod_wss
|
||||
|
||||
<VirtualHost _default_:80>
|
||||
|
||||
ErrorLog ${APACHE_LOG_DIR}/error.log
|
||||
CustomLog ${APACHE_LOG_DIR}/access.log combined
|
||||
|
||||
RewriteEngine on
|
||||
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
|
||||
</VirtualHost>
|
||||
|
||||
<VirtualHost _default_:443>
|
||||
|
||||
ErrorLog ${APACHE_LOG_DIR}/error.log
|
||||
CustomLog ${APACHE_LOG_DIR}/access.log combined
|
||||
|
||||
ProxyPreserveHost On
|
||||
SSLProxyEngine On
|
||||
SSLProxyVerify none
|
||||
SSLProxyCheckPeerCN off
|
||||
SSLProxyCheckPeerName off
|
||||
SSLProxyCheckPeerExpire off
|
||||
|
||||
#This is important for web sockets which are required by crafty to run!
|
||||
|
||||
RewriteEngine on
|
||||
RewriteCond %{HTTP:Upgrade} websocket [NC]
|
||||
RewriteCond %{HTTP:Connection} upgrade [NC]
|
||||
RewriteRule .* "wss://127.0.0.1:8443%{REQUEST_URI}" [P]
|
||||
|
||||
SSLCertificateFile /var/opt/minecraft/crafty4/app/config/web/certs/commander.cert.pem
|
||||
|
||||
SSLCertificateKeyFile /var/opt/minecraft/crafty4/app/config/web/certs/commander.key.pem
|
||||
|
||||
ProxyPass / https://127.0.0.1:8443/
|
||||
ProxyPassReverse / https://127.0.0.1:8443/
|
||||
ProxyRequests off
|
||||
</VirtualHost>
|
@ -3,8 +3,9 @@ version: '3'
|
||||
|
||||
services:
|
||||
crafty:
|
||||
container_name: crafty_commander
|
||||
image: registry.gitlab.com/crafty-controller/crafty-commander:latest
|
||||
container_name: crafty_container
|
||||
image: registry.gitlab.com/crafty-controller/crafty-4:latest
|
||||
restart: always
|
||||
environment:
|
||||
- TZ=Etc/UTC
|
||||
ports:
|
||||
@ -14,8 +15,8 @@ services:
|
||||
- "19132:19132/udp" # BEDROCK
|
||||
- "25500-25600:25500-25600" # MC SERV PORT RANGE
|
||||
volumes:
|
||||
- ./docker/backups:/commander/backups
|
||||
- ./docker/logs:/commander/logs
|
||||
- ./docker/servers:/commander/servers
|
||||
- ./docker/config:/commander/app/config
|
||||
- ./docker/import:/commander/import
|
||||
- ./docker/backups:/crafty/backups
|
||||
- ./docker/logs:/crafty/logs
|
||||
- ./docker/servers:/crafty/servers
|
||||
- ./docker/config:/crafty/app/config
|
||||
- ./docker/import:/crafty/import
|
||||
|
@ -3,19 +3,20 @@ version: '3'
|
||||
|
||||
services:
|
||||
crafty:
|
||||
container_name: crafty_commander
|
||||
container_name: crafty_container
|
||||
build: ..
|
||||
restart: always
|
||||
environment:
|
||||
- TZ=Etc/UTC
|
||||
ports:
|
||||
- "8000:8000" # HTTP
|
||||
- "8443:8443" # HTTPS
|
||||
- "8123:8123" # DYNMAP
|
||||
- "19132:19132/udp" # BEDROCK
|
||||
- "25500-25600:25500-25600" # MC SERV PORT RANGE
|
||||
- "8000:8000" # HTTP
|
||||
- "8443:8443" # HTTPS
|
||||
- "8123:8123" # DYNMAP
|
||||
- "19132:19132/udp" # BEDROCK
|
||||
- "25500-25600:25500-25600" # MC SERV PORT RANGE
|
||||
volumes:
|
||||
- ./backups:/commander/backups
|
||||
- ./logs:/commander/logs
|
||||
- ./servers:/commander/servers
|
||||
- ./config:/commander/app/config
|
||||
- ./import:/commander/import
|
||||
- ./backups:/crafty/backups
|
||||
- ./logs:/crafty/logs
|
||||
- ./servers:/crafty/servers
|
||||
- ./config:/crafty/app/config
|
||||
- ./import:/crafty/import
|
||||
|
@ -1,8 +1,8 @@
|
||||
<?xml version="1.0"?>
|
||||
<Container version="2">
|
||||
<Name>Crafty</Name>
|
||||
<Repository>crafty-controller/crafty-commander:latest</Repository>
|
||||
<Registry>registry.gitlab.com/crafty-controller/crafty-commander</Registry>
|
||||
<Repository>crafty-controller/crafty-4:latest</Repository>
|
||||
<Registry>registry.gitlab.com/crafty-controller/crafty-4</Registry>
|
||||
<Network>bridge</Network>
|
||||
<MyIP/>
|
||||
<Shell>sh</Shell>
|
||||
@ -13,12 +13,12 @@
|
||||
The username and password appear on the first launch in the Docker logs!
|
||||
Crafty 4 is the successor of Crafty Controller, the Docker image is no longer maintained on DockerHub. (now on GitLab)
|
||||
For official support join the discord: https://discord.gg/9VJPhCE
|
||||
For migration from 3.x please refer to the documentation on GitLab: https://gitlab.com/crafty-controller/crafty-commander/-/wikis/home
|
||||
For migration from 3.x please refer to the documentation on GitLab: https://wiki.craftycontrol.com/
|
||||
</Overview>
|
||||
<Category>GameServers: Other:</Category>
|
||||
<WebUI>https://[IP]:[PORT:8443]/</WebUI>
|
||||
<TemplateURL>https://gitlab.com/crafty-controller/crafty-commander/-/blob/dev/docker/unraid.xml</TemplateURL>
|
||||
<Icon>https://gitlab.com/crafty-controller/crafty-commander/-/raw/master/app/frontend/static/assets/images/logo_square.jpg</Icon>
|
||||
<TemplateURL>https://gitlab.com/crafty-controller/crafty-4/-/blob/dev/docker/unraid.xml</TemplateURL>
|
||||
<Icon>https://gitlab.com/crafty-controller/crafty-4/-/raw/master/app/frontend/static/assets/images/logo_square.jpg</Icon>
|
||||
<ExtraParams/>
|
||||
<PostArgs/>
|
||||
<CPUset/>
|
||||
@ -29,7 +29,7 @@ For migration from 3.x please refer to the documentation on GitLab: https://gitl
|
||||
The username and password appear on the first launch in the Docker logs!
|
||||
Crafty 4 is the successor of Crafty Controller, the Docker image is no longer maintained on DockerHub. (now on GitLab)
|
||||
For official support join the discord: https://discord.gg/9VJPhCE
|
||||
For migration from 3.x please refer to the documentation on GitLab: https://gitlab.com/crafty-controller/crafty-commander/-/wikis/home
|
||||
For migration from 3.x please refer to the documentation on GitLab: https://gitlab.com/crafty-controller/crafty-4/-/wikis/home
|
||||
</Description>
|
||||
<Networking>
|
||||
<Mode>bridge</Mode>
|
||||
@ -64,27 +64,27 @@ For migration from 3.x please refer to the documentation on GitLab: https://gitl
|
||||
<Data>
|
||||
<Volume>
|
||||
<HostDir>/mnt/user/appdata/Crafty-4/servers/</HostDir>
|
||||
<ContainerDir>/commander/servers</ContainerDir>
|
||||
<ContainerDir>/crafty/servers</ContainerDir>
|
||||
<Mode>rw</Mode>
|
||||
</Volume>
|
||||
<Volume>
|
||||
<HostDir>/mnt/user/appdata/Crafty-4/backups/</HostDir>
|
||||
<ContainerDir>/commander/backups</ContainerDir>
|
||||
<ContainerDir>/crafty/backups</ContainerDir>
|
||||
<Mode>rw</Mode>
|
||||
</Volume>
|
||||
<Volume>
|
||||
<HostDir>/mnt/user/appdata/Crafty-4/logs/</HostDir>
|
||||
<ContainerDir>/commander/logs</ContainerDir>
|
||||
<ContainerDir>/crafty/logs</ContainerDir>
|
||||
<Mode>rw</Mode>
|
||||
</Volume>
|
||||
<Volume>
|
||||
<HostDir>/mnt/user/appdata/Crafty-4/config/</HostDir>
|
||||
<ContainerDir>/commander/app/config</ContainerDir>
|
||||
<ContainerDir>/crafty/app/config</ContainerDir>
|
||||
<Mode>rw</Mode>
|
||||
</Volume>
|
||||
<Volume>
|
||||
<HostDir>/mnt/user/appdata/Crafty-4/import/</HostDir>
|
||||
<ContainerDir>/commander/import</ContainerDir>
|
||||
<ContainerDir>/crafty/import</ContainerDir>
|
||||
<Mode>rw</Mode>
|
||||
</Volume>
|
||||
</Data>
|
||||
@ -95,9 +95,9 @@ For migration from 3.x please refer to the documentation on GitLab: https://gitl
|
||||
<Config Name="Minecraft ports" Target="25500-25600" Default="25500-25600" Mode="tcp" Description="Container Port: 25500-25600 yes, 100 ports for 100 possible Servers" Type="Port" Display="always-hide" Required="true" Mask="false">25500-25600</Config>
|
||||
<Config Name="Port for dynmap" Target="8123" Default="8123" Mode="tcp" Description="Dynmap port" Type="Port" Display="always-hide" Required="true" Mask="false">8123</Config>
|
||||
<Config Name="Port for bedrock server" Target="19132" Default="19132" Mode="udp" Description="Bedrock server port" Type="Port" Display="always-hide" Required="true" Mask="false">19132</Config>
|
||||
<Config Name="Server files" Target="/commander/servers" Default="/mnt/user/appdata/Crafty-4/servers/" Mode="rw" Description="Path to the minecraft server folders" Type="Path" Display="always-hide" Required="true" Mask="false">/mnt/user/appdata/Crafty-4/servers/</Config>
|
||||
<Config Name="Backup files" Target="/commander/backups" Default="/mnt/user/appdata/Crafty-4/backups/" Mode="rw" Description="Server Backups" Type="Path" Display="always-hide" Required="true" Mask="false">/mnt/user/appdata/Crafty-4/backups/</Config>
|
||||
<Config Name="Server Logs" Target="/commander/logs" Default="/mnt/user/appdata/Crafty-4/logs/" Mode="rw" Description="Logs" Type="Path" Display="advanced-hide" Required="true" Mask="false">/mnt/user/appdata/Crafty-4/logs/</Config>
|
||||
<Config Name="Crafty Configuration" Target="/commander/app/config" Default="/mnt/user/appdata/Crafty-4/config/" Mode="rw" Description="Path to the persistent Crafty files" Type="Path" Display="advanced-hide" Required="true" Mask="false">/mnt/user/appdata/Crafty-4/config/</Config>
|
||||
<Config Name="Import folder" Target="/commander/import" Default="/mnt/user/appdata/Crafty-4/import/" Mode="rw" Description="Imports" Type="Path" Display="advanced-hide" Required="true" Mask="false">/mnt/user/appdata/Crafty-4/import/</Config>
|
||||
<Config Name="Server files" Target="/crafty/servers" Default="/mnt/user/appdata/Crafty-4/servers/" Mode="rw" Description="Path to the minecraft server folders" Type="Path" Display="always-hide" Required="true" Mask="false">/mnt/user/appdata/Crafty-4/servers/</Config>
|
||||
<Config Name="Backup files" Target="/crafty/backups" Default="/mnt/user/appdata/Crafty-4/backups/" Mode="rw" Description="Server Backups" Type="Path" Display="always-hide" Required="true" Mask="false">/mnt/user/appdata/Crafty-4/backups/</Config>
|
||||
<Config Name="Server Logs" Target="/crafty/logs" Default="/mnt/user/appdata/Crafty-4/logs/" Mode="rw" Description="Logs" Type="Path" Display="advanced-hide" Required="true" Mask="false">/mnt/user/appdata/Crafty-4/logs/</Config>
|
||||
<Config Name="Crafty Configuration" Target="/crafty/app/config" Default="/mnt/user/appdata/Crafty-4/config/" Mode="rw" Description="Path to the persistent Crafty files" Type="Path" Display="advanced-hide" Required="true" Mask="false">/mnt/user/appdata/Crafty-4/config/</Config>
|
||||
<Config Name="Import folder" Target="/crafty/import" Default="/mnt/user/appdata/Crafty-4/import/" Mode="rw" Description="Imports" Type="Path" Display="advanced-hide" Required="true" Mask="false">/mnt/user/appdata/Crafty-4/import/</Config>
|
||||
</Container>
|
||||
|
77
main.py
77
main.py
@ -5,24 +5,31 @@ import time
|
||||
import argparse
|
||||
import logging.config
|
||||
import signal
|
||||
from app.classes.shared.console import console
|
||||
from app.classes.shared.helpers import helper
|
||||
import peewee
|
||||
from app.classes.models.users import HelperUsers
|
||||
from app.classes.shared.console import Console
|
||||
from app.classes.shared.helpers import Helpers
|
||||
|
||||
if helper.checkRoot():
|
||||
console.critical(
|
||||
console = Console()
|
||||
helper = Helpers()
|
||||
if helper.check_root():
|
||||
Console.critical(
|
||||
"Root detected. Root/Admin access denied. "
|
||||
"Run Crafty again with non-elevated permissions."
|
||||
)
|
||||
time.sleep(5)
|
||||
console.critical("Crafty shutting down. Root/Admin access denied.")
|
||||
Console.critical("Crafty shutting down. Root/Admin access denied.")
|
||||
sys.exit(0)
|
||||
# pylint: disable=wrong-import-position
|
||||
from app.classes.shared.main_models import installer, database
|
||||
from app.classes.shared.tasks import TasksManager
|
||||
from app.classes.shared.main_controller import Controller
|
||||
from app.classes.shared.migration import MigrationManager
|
||||
|
||||
from app.classes.shared.command import MainPrompt
|
||||
try:
|
||||
from app.classes.models.base_model import database_proxy
|
||||
from app.classes.shared.main_models import DatabaseBuilder
|
||||
from app.classes.shared.tasks import TasksManager
|
||||
from app.classes.shared.main_controller import Controller
|
||||
from app.classes.shared.migration import MigrationManager
|
||||
from app.classes.shared.command import MainPrompt
|
||||
except ModuleNotFoundError as err:
|
||||
helper.auto_installer_fix(err)
|
||||
|
||||
|
||||
def do_intro():
|
||||
@ -39,7 +46,7 @@ def do_intro():
|
||||
{'/' * 75}
|
||||
"""
|
||||
|
||||
console.magenta(intro)
|
||||
Console.magenta(intro)
|
||||
|
||||
|
||||
def setup_logging(debug=True):
|
||||
@ -57,7 +64,7 @@ def setup_logging(debug=True):
|
||||
else:
|
||||
logging.basicConfig(level=logging.DEBUG)
|
||||
logging.warning(f"Unable to read logging config from {logging_config_file}")
|
||||
console.critical(f"Unable to read logging config from {logging_config_file}")
|
||||
Console.critical(f"Unable to read logging config from {logging_config_file}")
|
||||
|
||||
|
||||
# Our Main Starter
|
||||
@ -87,7 +94,9 @@ if __name__ == "__main__":
|
||||
|
||||
# setting up the logger object
|
||||
logger = logging.getLogger(__name__)
|
||||
console.cyan(f"Logging set to: {logger.level}")
|
||||
Console.cyan(f"Logging set to: {logger.level}")
|
||||
peewee_logger = logging.getLogger("peewee")
|
||||
peewee_logger.setLevel(logging.INFO)
|
||||
|
||||
# print our pretty start message
|
||||
do_intro()
|
||||
@ -95,15 +104,23 @@ if __name__ == "__main__":
|
||||
# our session file, helps prevent multiple controller agents on the same machine.
|
||||
helper.create_session_file(ignore=args.ignore)
|
||||
|
||||
migration_manager = MigrationManager(database)
|
||||
# start the database
|
||||
database = peewee.SqliteDatabase(
|
||||
helper.db_path, pragmas={"journal_mode": "wal", "cache_size": -1024 * 10}
|
||||
)
|
||||
database_proxy.initialize(database)
|
||||
|
||||
migration_manager = MigrationManager(database, helper)
|
||||
migration_manager.up() # Automatically runs migrations
|
||||
|
||||
# do our installer stuff
|
||||
fresh_install = installer.is_fresh_install()
|
||||
user_helper = HelperUsers(database, helper)
|
||||
installer = DatabaseBuilder(database, helper, user_helper)
|
||||
FRESH_INSTALL = installer.is_fresh_install()
|
||||
|
||||
if fresh_install:
|
||||
console.debug("Fresh install detected")
|
||||
console.warning(
|
||||
if FRESH_INSTALL:
|
||||
Console.debug("Fresh install detected")
|
||||
Console.warning(
|
||||
f"We have detected a fresh install. Please be sure to forward "
|
||||
f"Crafty's port, {helper.get_setting('https_port')}, "
|
||||
f"through your router/firewall if you would like to be able "
|
||||
@ -111,11 +128,11 @@ if __name__ == "__main__":
|
||||
)
|
||||
installer.default_settings()
|
||||
else:
|
||||
console.debug("Existing install detected")
|
||||
Console.debug("Existing install detected")
|
||||
|
||||
# now the tables are created, we can load the tasks_manger and server controller
|
||||
controller = Controller()
|
||||
tasks_manager = TasksManager(controller)
|
||||
# now the tables are created, we can load the tasks_manager and server controller
|
||||
controller = Controller(database, helper)
|
||||
tasks_manager = TasksManager(helper, controller)
|
||||
tasks_manager.start_webserver()
|
||||
|
||||
# slowing down reporting just for a 1/2 second so messages look cleaner
|
||||
@ -123,7 +140,7 @@ if __name__ == "__main__":
|
||||
|
||||
# init servers
|
||||
logger.info("Initializing all servers defined")
|
||||
console.info("Initializing all servers defined")
|
||||
Console.info("Initializing all servers defined")
|
||||
controller.init_all_servers()
|
||||
servers = controller.list_defined_servers()
|
||||
|
||||
@ -139,10 +156,10 @@ if __name__ == "__main__":
|
||||
tasks_manager.serverjar_cache_refresher()
|
||||
|
||||
logger.info("Checking Internet. This may take a minute.")
|
||||
console.info("Checking Internet. This may take a minute.")
|
||||
Console.info("Checking Internet. This may take a minute.")
|
||||
|
||||
if not helper.check_internet():
|
||||
console.warning(
|
||||
Console.warning(
|
||||
"We have detected the machine running Crafty has no "
|
||||
"connection to the internet. Client connections to "
|
||||
"the server may be limited."
|
||||
@ -151,7 +168,7 @@ if __name__ == "__main__":
|
||||
if not controller.check_system_user():
|
||||
controller.add_system_user()
|
||||
|
||||
Crafty = MainPrompt(tasks_manager, migration_manager)
|
||||
Crafty = MainPrompt(helper, tasks_manager, migration_manager)
|
||||
|
||||
project_root = os.path.dirname(__file__)
|
||||
controller.set_project_root(project_root)
|
||||
@ -163,7 +180,7 @@ if __name__ == "__main__":
|
||||
logger.info(
|
||||
f"Recieved {signal.Signals(sig[0]).name} [{sig[0]}], stopping Crafty..."
|
||||
)
|
||||
console.info(
|
||||
Console.info(
|
||||
f"Recieved {signal.Signals(sig[0]).name} [{sig[0]}], stopping Crafty..."
|
||||
)
|
||||
tasks_manager._main_graceful_exit()
|
||||
@ -177,7 +194,7 @@ if __name__ == "__main__":
|
||||
except KeyboardInterrupt:
|
||||
print() # for newline
|
||||
logger.info("Recieved SIGINT, stopping Crafty...")
|
||||
console.info("Recieved SIGINT, stopping Crafty...")
|
||||
Console.info("Recieved SIGINT, stopping Crafty...")
|
||||
tasks_manager._main_graceful_exit()
|
||||
Crafty.universal_exit()
|
||||
else:
|
||||
@ -189,7 +206,7 @@ if __name__ == "__main__":
|
||||
time.sleep(1)
|
||||
except KeyboardInterrupt:
|
||||
logger.info("Recieved SIGINT, stopping Crafty...")
|
||||
console.info("Recieved SIGINT, stopping Crafty...")
|
||||
Console.info("Recieved SIGINT, stopping Crafty...")
|
||||
break
|
||||
tasks_manager._main_graceful_exit()
|
||||
Crafty.universal_exit()
|
||||
|
@ -5,7 +5,7 @@ bleach==4.1
|
||||
cached_property==1.5.2
|
||||
colorama==0.4
|
||||
cron-validator==1.0.3
|
||||
cryptography==3.4
|
||||
cryptography==3.4.8
|
||||
libgravatar==1.0.0
|
||||
peewee==3.13
|
||||
pexpect==4.8
|
||||
|
Loading…
Reference in New Issue
Block a user