mirror of
https://gitlab.com/crafty-controller/crafty-4.git
synced 2024-08-30 18:23:09 +00:00
Create pylintrc, code review pipeline & correct codebase errors
Fix uploads, Only send server stats to user page when they have access to servers
This commit is contained in:
parent
882126d1f3
commit
e0ce1d118c
@ -1,4 +1,5 @@
|
||||
stages:
|
||||
- test
|
||||
- prod-deployment
|
||||
- dev-deployment
|
||||
|
||||
@ -6,6 +7,36 @@ variables:
|
||||
DOCKER_HOST: tcp://docker:2376
|
||||
DOCKER_TLS_CERTDIR: "/certs"
|
||||
|
||||
pylint:
|
||||
stage: test
|
||||
image: python:3.7-slim
|
||||
services:
|
||||
- name: docker:dind
|
||||
tags:
|
||||
- 'docker_testers'
|
||||
rules:
|
||||
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
|
||||
- if: '$CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS'
|
||||
when: never
|
||||
before_script:
|
||||
- mkdir -p public/badges public/lint
|
||||
- echo undefined > public/badges/$CI_JOB_NAME.score
|
||||
- pip install pylint-gitlab
|
||||
script:
|
||||
- pylint --exit-zero --output-format=text $(find -type f -name "*.py" ! -path "**/.venv/**" ! -path "**/app/migrations/**") | tee /tmp/pylint.txt
|
||||
- sed -n 's/^Your code has been rated at \([-0-9.]*\)\/.*/\1/p' /tmp/pylint.txt > public/badges/$CI_JOB_NAME.score
|
||||
- pylint --exit-zero --output-format=pylint_gitlab.GitlabCodeClimateReporter $(find -type f -name "*.py" ! -path "**/.venv/**" ! -path "**/app/migrations/**") > codeclimate.json
|
||||
after_script:
|
||||
- anybadge --overwrite --label $CI_JOB_NAME --value=$(cat public/badges/$CI_JOB_NAME.score) --file=public/badges/$CI_JOB_NAME.svg 4=red 6=orange 8=yellow 10=green
|
||||
- |
|
||||
echo "Your score is: $(cat public/badges/$CI_JOB_NAME.score)"
|
||||
artifacts:
|
||||
paths:
|
||||
- public
|
||||
reports:
|
||||
codequality: codeclimate.json
|
||||
when: always
|
||||
|
||||
docker-build-dev:
|
||||
image: docker:latest
|
||||
services:
|
||||
|
603
.pylintrc
Normal file
603
.pylintrc
Normal file
@ -0,0 +1,603 @@
|
||||
[MASTER]
|
||||
|
||||
# A comma-separated list of package or module names from where C extensions may
|
||||
# be loaded. Extensions are loading into the active Python interpreter and may
|
||||
# run arbitrary code.
|
||||
extension-pkg-allow-list=
|
||||
|
||||
# A comma-separated list of package or module names from where C extensions may
|
||||
# be loaded. Extensions are loading into the active Python interpreter and may
|
||||
# run arbitrary code. (This is an alternative name to extension-pkg-allow-list
|
||||
# for backward compatibility.)
|
||||
extension-pkg-whitelist=
|
||||
|
||||
# Return non-zero exit code if any of these messages/categories are detected,
|
||||
# even if score is above --fail-under value. Syntax same as enable. Messages
|
||||
# specified are enabled, while categories only check already-enabled messages.
|
||||
fail-on=
|
||||
|
||||
# Specify a score threshold to be exceeded before program exits with error.
|
||||
fail-under=10.0
|
||||
|
||||
# Files or directories to be skipped. They should be base names, not paths.
|
||||
ignore=
|
||||
|
||||
# Add files or directories matching the regex patterns to the ignore-list. The
|
||||
# regex matches against paths and can be in Posix or Windows format.
|
||||
ignore-paths=app/migrations
|
||||
|
||||
# Files or directories matching the regex patterns are skipped. The regex
|
||||
# matches against base names, not paths.
|
||||
ignore-patterns=
|
||||
|
||||
# Python code to execute, usually for sys.path manipulation such as
|
||||
# pygtk.require().
|
||||
#init-hook=
|
||||
|
||||
# Use multiple processes to speed up Pylint. Specifying 0 will auto-detect the
|
||||
# number of processors available to use.
|
||||
jobs=0
|
||||
|
||||
# Control the amount of potential inferred values when inferring a single
|
||||
# object. This can help the performance when dealing with large functions or
|
||||
# complex, nested conditions.
|
||||
limit-inference-results=100
|
||||
|
||||
# List of plugins (as comma separated values of python module names) to load,
|
||||
# usually to register additional checkers.
|
||||
load-plugins=
|
||||
|
||||
# Pickle collected data for later comparisons.
|
||||
persistent=yes
|
||||
|
||||
# Minimum Python version to use for version dependent checks. Will default to
|
||||
# the version used to run pylint.
|
||||
py-version=3.9
|
||||
|
||||
# When enabled, pylint would attempt to guess common misconfiguration and emit
|
||||
# user-friendly hints instead of false-positive error messages.
|
||||
suggestion-mode=yes
|
||||
|
||||
# Allow loading of arbitrary C extensions. Extensions are imported into the
|
||||
# active Python interpreter and may run arbitrary code.
|
||||
unsafe-load-any-extension=no
|
||||
|
||||
|
||||
[MESSAGES CONTROL]
|
||||
|
||||
# Only show warnings with the listed confidence levels. Leave empty to show
|
||||
# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED.
|
||||
confidence=
|
||||
|
||||
# Disable the message, report, category or checker with the given id(s). You
|
||||
# can either give multiple identifiers separated by comma (,) or put this
|
||||
# option multiple times (only on the command line, not in the configuration
|
||||
# file where it should appear only once). You can also use "--disable=all" to
|
||||
# disable everything first and then reenable specific checks. For example, if
|
||||
# you want to run only the similarities checker, you can use "--disable=all
|
||||
# --enable=similarities". If you want to run only the classes checker, but have
|
||||
# no Warning level messages displayed, use "--disable=all --enable=classes
|
||||
# --disable=W".
|
||||
disable=abstract-method,
|
||||
attribute-defined-outside-init,
|
||||
bad-inline-option,
|
||||
bare-except,
|
||||
broad-except,
|
||||
cell-var-from-loop,
|
||||
consider-iterating-dictionary,
|
||||
consider-using-with,
|
||||
deprecated-pragma,
|
||||
duplicate-code,
|
||||
file-ignored,
|
||||
fixme,
|
||||
import-error,
|
||||
inconsistent-return-statements,
|
||||
invalid-name,
|
||||
locally-disabled,
|
||||
logging-format-interpolation,
|
||||
logging-fstring-interpolation,
|
||||
logging-not-lazy,
|
||||
missing-docstring,
|
||||
no-else-break,
|
||||
no-else-continue,
|
||||
no-else-return,
|
||||
no-self-use,
|
||||
no-value-for-parameter,
|
||||
not-an-iterable,
|
||||
protected-access,
|
||||
simplifiable-condition,
|
||||
simplifiable-if-statement,
|
||||
suppressed-message,
|
||||
too-few-public-methods,
|
||||
too-many-arguments,
|
||||
too-many-branches,
|
||||
too-many-instance-attributes,
|
||||
too-many-locals,
|
||||
too-many-nested-blocks,
|
||||
too-many-public-methods,
|
||||
too-many-return-statements,
|
||||
too-many-statements,
|
||||
use-symbolic-message-instead,
|
||||
useless-suppression,
|
||||
raw-checker-failed
|
||||
|
||||
|
||||
# Enable the message, report, category or checker with the given id(s). You can
|
||||
# either give multiple identifier separated by comma (,) or put this option
|
||||
# multiple time (only on the command line, not in the configuration file where
|
||||
# it should appear only once). See also the "--disable" option for examples.
|
||||
enable=c-extension-no-member
|
||||
|
||||
|
||||
[REPORTS]
|
||||
|
||||
# Python expression which should return a score less than or equal to 10. You
|
||||
# have access to the variables 'error', 'warning', 'refactor', and 'convention'
|
||||
# which contain the number of messages in each category, as well as 'statement'
|
||||
# which is the total number of statements analyzed. This score is used by the
|
||||
# global evaluation report (RP0004).
|
||||
evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
|
||||
|
||||
# Template used to display messages. This is a python new-style format string
|
||||
# used to format the message information. See doc for all details.
|
||||
#msg-template=
|
||||
|
||||
# Set the output format. Available formats are text, parseable, colorized, json
|
||||
# and msvs (visual studio). You can also give a reporter class, e.g.
|
||||
# mypackage.mymodule.MyReporterClass.
|
||||
output-format=text
|
||||
|
||||
# Tells whether to display a full report or only the messages.
|
||||
reports=no
|
||||
|
||||
# Activate the evaluation score.
|
||||
score=yes
|
||||
|
||||
|
||||
[REFACTORING]
|
||||
|
||||
# Maximum number of nested blocks for function / method body
|
||||
max-nested-blocks=5
|
||||
|
||||
# Complete name of functions that never returns. When checking for
|
||||
# inconsistent-return-statements if a never returning function is called then
|
||||
# it will be considered as an explicit return statement and no message will be
|
||||
# printed.
|
||||
never-returning-functions=sys.exit,argparse.parse_error
|
||||
|
||||
|
||||
[BASIC]
|
||||
|
||||
# Naming style matching correct argument names.
|
||||
argument-naming-style=snake_case
|
||||
|
||||
# Regular expression matching correct argument names. Overrides argument-
|
||||
# naming-style.
|
||||
#argument-rgx=
|
||||
|
||||
# Naming style matching correct attribute names.
|
||||
attr-naming-style=snake_case
|
||||
|
||||
# Regular expression matching correct attribute names. Overrides attr-naming-
|
||||
# style.
|
||||
#attr-rgx=
|
||||
|
||||
# Bad variable names which should always be refused, separated by a comma.
|
||||
bad-names=foo,
|
||||
bar,
|
||||
baz,
|
||||
toto,
|
||||
tutu,
|
||||
tata
|
||||
|
||||
# Bad variable names regexes, separated by a comma. If names match any regex,
|
||||
# they will always be refused
|
||||
bad-names-rgxs=
|
||||
|
||||
# Naming style matching correct class attribute names.
|
||||
class-attribute-naming-style=any
|
||||
|
||||
# Regular expression matching correct class attribute names. Overrides class-
|
||||
# attribute-naming-style.
|
||||
#class-attribute-rgx=
|
||||
|
||||
# Naming style matching correct class constant names.
|
||||
class-const-naming-style=UPPER_CASE
|
||||
|
||||
# Regular expression matching correct class constant names. Overrides class-
|
||||
# const-naming-style.
|
||||
#class-const-rgx=
|
||||
|
||||
# Naming style matching correct class names.
|
||||
class-naming-style=PascalCase
|
||||
|
||||
# Regular expression matching correct class names. Overrides class-naming-
|
||||
# style.
|
||||
#class-rgx=
|
||||
|
||||
# Naming style matching correct constant names.
|
||||
const-naming-style=UPPER_CASE
|
||||
|
||||
# Regular expression matching correct constant names. Overrides const-naming-
|
||||
# style.
|
||||
#const-rgx=
|
||||
|
||||
# Minimum line length for functions/classes that require docstrings, shorter
|
||||
# ones are exempt.
|
||||
docstring-min-length=-1
|
||||
|
||||
# Naming style matching correct function names.
|
||||
function-naming-style=snake_case
|
||||
|
||||
# Regular expression matching correct function names. Overrides function-
|
||||
# naming-style.
|
||||
#function-rgx=
|
||||
|
||||
# Good variable names which should always be accepted, separated by a comma.
|
||||
good-names=i,
|
||||
j,
|
||||
k,
|
||||
ex,
|
||||
Run,
|
||||
_
|
||||
|
||||
# Good variable names regexes, separated by a comma. If names match any regex,
|
||||
# they will always be accepted
|
||||
good-names-rgxs=
|
||||
|
||||
# Include a hint for the correct naming format with invalid-name.
|
||||
include-naming-hint=no
|
||||
|
||||
# Naming style matching correct inline iteration names.
|
||||
inlinevar-naming-style=any
|
||||
|
||||
# Regular expression matching correct inline iteration names. Overrides
|
||||
# inlinevar-naming-style.
|
||||
#inlinevar-rgx=
|
||||
|
||||
# Naming style matching correct method names.
|
||||
method-naming-style=snake_case
|
||||
|
||||
# Regular expression matching correct method names. Overrides method-naming-
|
||||
# style.
|
||||
#method-rgx=
|
||||
|
||||
# Naming style matching correct module names.
|
||||
module-naming-style=snake_case
|
||||
|
||||
# Regular expression matching correct module names. Overrides module-naming-
|
||||
# style.
|
||||
#module-rgx=
|
||||
|
||||
# Colon-delimited sets of names that determine each other's naming style when
|
||||
# the name regexes allow several styles.
|
||||
name-group=
|
||||
|
||||
# Regular expression which should only match function or class names that do
|
||||
# not require a docstring.
|
||||
no-docstring-rgx=^_
|
||||
|
||||
# List of decorators that produce properties, such as abc.abstractproperty. Add
|
||||
# to this list to register other decorators that produce valid properties.
|
||||
# These decorators are taken in consideration only for invalid-name.
|
||||
property-classes=abc.abstractproperty
|
||||
|
||||
# Naming style matching correct variable names.
|
||||
variable-naming-style=snake_case
|
||||
|
||||
# Regular expression matching correct variable names. Overrides variable-
|
||||
# naming-style.
|
||||
#variable-rgx=
|
||||
|
||||
|
||||
[FORMAT]
|
||||
|
||||
# Expected format of line ending, e.g. empty (any line ending), LF or CRLF.
|
||||
expected-line-ending-format=
|
||||
|
||||
# Regexp for a line that is allowed to be longer than the limit.
|
||||
ignore-long-lines=^\s*(# )?<?https?://\S+>?$
|
||||
|
||||
# Number of spaces of indent required inside a hanging or continued line.
|
||||
indent-after-paren=4
|
||||
|
||||
# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
|
||||
# tab).
|
||||
indent-string=' '
|
||||
|
||||
# Maximum number of characters on a single line.
|
||||
max-line-length=150
|
||||
|
||||
# Maximum number of lines in a module.
|
||||
max-module-lines=2000
|
||||
|
||||
# Allow the body of a class to be on the same line as the declaration if body
|
||||
# contains single statement.
|
||||
single-line-class-stmt=no
|
||||
|
||||
# Allow the body of an if to be on the same line as the test if there is no
|
||||
# else.
|
||||
single-line-if-stmt=no
|
||||
|
||||
|
||||
[LOGGING]
|
||||
|
||||
# The type of string formatting that logging methods do. `old` means using %
|
||||
# formatting, `new` is for `{}` formatting.
|
||||
logging-format-style=old
|
||||
|
||||
# Logging modules to check that the string format arguments are in logging
|
||||
# function parameter format.
|
||||
logging-modules=logging
|
||||
|
||||
|
||||
[MISCELLANEOUS]
|
||||
|
||||
# List of note tags to take in consideration, separated by a comma.
|
||||
notes=FIXME,
|
||||
XXX,
|
||||
TODO
|
||||
|
||||
# Regular expression of note tags to take in consideration.
|
||||
#notes-rgx=
|
||||
|
||||
|
||||
[SIMILARITIES]
|
||||
|
||||
# Comments are removed from the similarity computation
|
||||
ignore-comments=yes
|
||||
|
||||
# Docstrings are removed from the similarity computation
|
||||
ignore-docstrings=yes
|
||||
|
||||
# Imports are removed from the similarity computation
|
||||
ignore-imports=no
|
||||
|
||||
# Signatures are removed from the similarity computation
|
||||
ignore-signatures=no
|
||||
|
||||
# Minimum lines number of a similarity.
|
||||
min-similarity-lines=4
|
||||
|
||||
|
||||
[SPELLING]
|
||||
|
||||
# Limits count of emitted suggestions for spelling mistakes.
|
||||
max-spelling-suggestions=4
|
||||
|
||||
# Spelling dictionary name. Available dictionaries: none. To make it work,
|
||||
# install the 'python-enchant' package.
|
||||
spelling-dict=
|
||||
|
||||
# List of comma separated words that should be considered directives if they
|
||||
# appear and the beginning of a comment and should not be checked.
|
||||
spelling-ignore-comment-directives=fmt: on,fmt: off,noqa:,noqa,nosec,isort:skip,mypy:
|
||||
|
||||
# List of comma separated words that should not be checked.
|
||||
spelling-ignore-words=
|
||||
|
||||
# A path to a file that contains the private dictionary; one word per line.
|
||||
spelling-private-dict-file=
|
||||
|
||||
# Tells whether to store unknown words to the private dictionary (see the
|
||||
# --spelling-private-dict-file option) instead of raising a message.
|
||||
spelling-store-unknown-words=no
|
||||
|
||||
|
||||
[STRING]
|
||||
|
||||
# This flag controls whether inconsistent-quotes generates a warning when the
|
||||
# character used as a quote delimiter is used inconsistently within a module.
|
||||
check-quote-consistency=no
|
||||
|
||||
# This flag controls whether the implicit-str-concat should generate a warning
|
||||
# on implicit string concatenation in sequences defined over several lines.
|
||||
check-str-concat-over-line-jumps=no
|
||||
|
||||
|
||||
[TYPECHECK]
|
||||
|
||||
# List of decorators that produce context managers, such as
|
||||
# contextlib.contextmanager. Add to this list to register other decorators that
|
||||
# produce valid context managers.
|
||||
contextmanager-decorators=contextlib.contextmanager
|
||||
|
||||
# List of members which are set dynamically and missed by pylint inference
|
||||
# system, and so shouldn't trigger E1101 when accessed. Python regular
|
||||
# expressions are accepted.
|
||||
generated-members=os.*
|
||||
|
||||
# Tells whether missing members accessed in mixin class should be ignored. A
|
||||
# class is considered mixin if its name matches the mixin-class-rgx option.
|
||||
ignore-mixin-members=yes
|
||||
|
||||
# Tells whether to warn about missing members when the owner of the attribute
|
||||
# is inferred to be None.
|
||||
ignore-none=yes
|
||||
|
||||
# This flag controls whether pylint should warn about no-member and similar
|
||||
# checks whenever an opaque object is returned when inferring. The inference
|
||||
# can return multiple potential results while evaluating a Python object, but
|
||||
# some branches might not be evaluated, which results in partial inference. In
|
||||
# that case, it might be useful to still emit no-member and other checks for
|
||||
# the rest of the inferred objects.
|
||||
ignore-on-opaque-inference=yes
|
||||
|
||||
# List of class names for which member attributes should not be checked (useful
|
||||
# for classes with dynamically set attributes). This supports the use of
|
||||
# qualified names.
|
||||
ignored-classes=optparse.Values,thread._local,_thread._local
|
||||
|
||||
# List of module names for which member attributes should not be checked
|
||||
# (useful for modules/projects where namespaces are manipulated during runtime
|
||||
# and thus existing member attributes cannot be deduced by static analysis). It
|
||||
# supports qualified module names, as well as Unix pattern matching.
|
||||
ignored-modules=
|
||||
|
||||
# Show a hint with possible names when a member name was not found. The aspect
|
||||
# of finding the hint is based on edit distance.
|
||||
missing-member-hint=yes
|
||||
|
||||
# The minimum edit distance a name should have in order to be considered a
|
||||
# similar match for a missing member name.
|
||||
missing-member-hint-distance=1
|
||||
|
||||
# The total number of similar names that should be taken in consideration when
|
||||
# showing a hint for a missing member.
|
||||
missing-member-max-choices=1
|
||||
|
||||
# Regex pattern to define which classes are considered mixins ignore-mixin-
|
||||
# members is set to 'yes'
|
||||
mixin-class-rgx=.*[Mm]ixin
|
||||
|
||||
# List of decorators that change the signature of a decorated function.
|
||||
signature-mutators=
|
||||
|
||||
|
||||
[VARIABLES]
|
||||
|
||||
# List of additional names supposed to be defined in builtins. Remember that
|
||||
# you should avoid defining new builtins when possible.
|
||||
additional-builtins=
|
||||
|
||||
# Tells whether unused global variables should be treated as a violation.
|
||||
allow-global-unused-variables=yes
|
||||
|
||||
# List of names allowed to shadow builtins
|
||||
allowed-redefined-builtins=
|
||||
|
||||
# List of strings which can identify a callback function by name. A callback
|
||||
# name must start or end with one of those strings.
|
||||
callbacks=cb_,
|
||||
_cb
|
||||
|
||||
# A regular expression matching the name of dummy variables (i.e. expected to
|
||||
# not be used).
|
||||
dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_
|
||||
|
||||
# Argument names that match this expression will be ignored. Default to name
|
||||
# with leading underscore.
|
||||
ignored-argument-names=_.*|^ignored_|^unused_
|
||||
|
||||
# Tells whether we should check for unused import in __init__ files.
|
||||
init-import=no
|
||||
|
||||
# List of qualified module names which can have objects that can redefine
|
||||
# builtins.
|
||||
redefining-builtins-modules=six.moves,past.builtins,future.builtins,builtins,io
|
||||
|
||||
|
||||
[CLASSES]
|
||||
|
||||
# Warn about protected attribute access inside special methods
|
||||
check-protected-access-in-special-methods=no
|
||||
|
||||
# List of method names used to declare (i.e. assign) instance attributes.
|
||||
defining-attr-methods=__init__,
|
||||
__new__,
|
||||
setUp,
|
||||
__post_init__
|
||||
|
||||
# List of member names, which should be excluded from the protected access
|
||||
# warning.
|
||||
exclude-protected=_asdict,
|
||||
_fields,
|
||||
_replace,
|
||||
_source,
|
||||
_make
|
||||
|
||||
# List of valid names for the first argument in a class method.
|
||||
valid-classmethod-first-arg=cls
|
||||
|
||||
# List of valid names for the first argument in a metaclass class method.
|
||||
valid-metaclass-classmethod-first-arg=cls
|
||||
|
||||
|
||||
[DESIGN]
|
||||
|
||||
# List of regular expressions of class ancestor names to ignore when counting
|
||||
# public methods (see R0903)
|
||||
exclude-too-few-public-methods=
|
||||
|
||||
# List of qualified class names to ignore when counting class parents (see
|
||||
# R0901)
|
||||
ignored-parents=
|
||||
|
||||
# Maximum number of arguments for function / method.
|
||||
max-args=8
|
||||
|
||||
# Maximum number of attributes for a class (see R0902).
|
||||
max-attributes=7
|
||||
|
||||
# Maximum number of boolean expressions in an if statement (see R0916).
|
||||
max-bool-expr=5
|
||||
|
||||
# Maximum number of branch for function / method body.
|
||||
max-branches=12
|
||||
|
||||
# Maximum number of locals for function / method body.
|
||||
max-locals=15
|
||||
|
||||
# Maximum number of parents for a class (see R0901).
|
||||
max-parents=7
|
||||
|
||||
# Maximum number of public methods for a class (see R0904).
|
||||
max-public-methods=20
|
||||
|
||||
# Maximum number of return / yield for function / method body.
|
||||
max-returns=6
|
||||
|
||||
# Maximum number of statements in function / method body.
|
||||
max-statements=50
|
||||
|
||||
# Minimum number of public methods for a class (see R0903).
|
||||
min-public-methods=2
|
||||
|
||||
|
||||
[IMPORTS]
|
||||
|
||||
# List of modules that can be imported at any level, not just the top level
|
||||
# one.
|
||||
allow-any-import-level=
|
||||
|
||||
# Allow wildcard imports from modules that define __all__.
|
||||
allow-wildcard-with-all=no
|
||||
|
||||
# Analyse import fallback blocks. This can be used to support both Python 2 and
|
||||
# 3 compatible code, which means that the block might have code that exists
|
||||
# only in one or another interpreter, leading to false positives when analysed.
|
||||
analyse-fallback-blocks=no
|
||||
|
||||
# Deprecated modules which should not be used, separated by a comma.
|
||||
deprecated-modules=
|
||||
|
||||
# Output a graph (.gv or any supported image format) of external dependencies
|
||||
# to the given file (report RP0402 must not be disabled).
|
||||
ext-import-graph=
|
||||
|
||||
# Output a graph (.gv or any supported image format) of all (i.e. internal and
|
||||
# external) dependencies to the given file (report RP0402 must not be
|
||||
# disabled).
|
||||
import-graph=
|
||||
|
||||
# Output a graph (.gv or any supported image format) of internal dependencies
|
||||
# to the given file (report RP0402 must not be disabled).
|
||||
int-import-graph=
|
||||
|
||||
# Force import order to recognize a module as part of the standard
|
||||
# compatibility libraries.
|
||||
known-standard-library=
|
||||
|
||||
# Force import order to recognize a module as part of a third party library.
|
||||
known-third-party=enchant
|
||||
|
||||
# Couples of modules and preferred modules, separated by a comma.
|
||||
preferred-modules=
|
||||
|
||||
|
||||
[EXCEPTIONS]
|
||||
|
||||
# Exceptions that will emit a warning when being caught. Defaults to
|
||||
# "BaseException, Exception".
|
||||
overgeneral-exceptions=BaseException,
|
||||
Exception
|
@ -1,23 +1,6 @@
|
||||
import os
|
||||
import time
|
||||
import logging
|
||||
import sys
|
||||
import yaml
|
||||
import asyncio
|
||||
import shutil
|
||||
import tempfile
|
||||
import zipfile
|
||||
from distutils import dir_util
|
||||
|
||||
from app.classes.shared.helpers import helper
|
||||
from app.classes.shared.console import console
|
||||
|
||||
from app.classes.models.crafty_permissions import crafty_permissions, Enum_Permissions_Crafty
|
||||
|
||||
from app.classes.shared.server import Server
|
||||
from app.classes.minecraft.server_props import ServerProps
|
||||
from app.classes.minecraft.serverjars import server_jar_obj
|
||||
from app.classes.minecraft.stats import Stats
|
||||
from app.classes.models.users import ApiKeys
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@ -43,13 +26,13 @@ class Crafty_Perms_Controller:
|
||||
return crafty_permissions.can_add_in_crafty(user_id, Enum_Permissions_Crafty.Server_Creation)
|
||||
|
||||
@staticmethod
|
||||
def can_add_user(user_id):
|
||||
def can_add_user(): # Add back argument 'user_id' when you work on this
|
||||
#TODO: Complete if we need a User Addition limit
|
||||
#return crafty_permissions.can_add_in_crafty(user_id, Enum_Permissions_Crafty.User_Config)
|
||||
return True
|
||||
|
||||
@staticmethod
|
||||
def can_add_role(user_id):
|
||||
def can_add_role(): # Add back argument 'user_id' when you work on this
|
||||
#TODO: Complete if we need a Role Addition limit
|
||||
#return crafty_permissions.can_add_in_crafty(user_id, Enum_Permissions_Crafty.Roles_Config)
|
||||
return True
|
||||
|
@ -1,25 +1,8 @@
|
||||
import os
|
||||
import time
|
||||
import logging
|
||||
import sys
|
||||
import yaml
|
||||
import asyncio
|
||||
import shutil
|
||||
import tempfile
|
||||
import zipfile
|
||||
from distutils import dir_util
|
||||
|
||||
from app.classes.shared.helpers import helper
|
||||
from app.classes.shared.console import console
|
||||
|
||||
from app.classes.models.management import management_helper
|
||||
from app.classes.models.servers import servers_helper
|
||||
|
||||
from app.classes.shared.server import Server
|
||||
from app.classes.minecraft.server_props import ServerProps
|
||||
from app.classes.minecraft.serverjars import server_jar_obj
|
||||
from app.classes.minecraft.stats import Stats
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class Management_Controller:
|
||||
@ -43,8 +26,7 @@ class Management_Controller:
|
||||
server_name = servers_helper.get_server_friendly_name(server_id)
|
||||
|
||||
# Example: Admin issued command start_server for server Survival
|
||||
management_helper.add_to_audit_log(user_id, "issued command {} for server {}".format(command, server_name),
|
||||
server_id, remote_ip)
|
||||
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)
|
||||
|
||||
@staticmethod
|
||||
@ -71,7 +53,16 @@ class Management_Controller:
|
||||
#************************************************************************************************
|
||||
@staticmethod
|
||||
def create_scheduled_task(server_id, action, interval, interval_type, start_time, command, comment=None, enabled=True):
|
||||
return management_helper.create_scheduled_task(server_id, action, interval, interval_type, start_time, command, comment, enabled)
|
||||
return management_helper.create_scheduled_task(
|
||||
server_id,
|
||||
action,
|
||||
interval,
|
||||
interval_type,
|
||||
start_time,
|
||||
command,
|
||||
comment,
|
||||
enabled
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def delete_scheduled_task(schedule_id):
|
||||
|
@ -1,25 +1,10 @@
|
||||
import os
|
||||
import time
|
||||
import logging
|
||||
import sys
|
||||
import yaml
|
||||
import asyncio
|
||||
import shutil
|
||||
import tempfile
|
||||
import zipfile
|
||||
from distutils import dir_util
|
||||
|
||||
from app.classes.shared.helpers import helper
|
||||
from app.classes.shared.console import console
|
||||
|
||||
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.server import Server
|
||||
from app.classes.minecraft.server_props import ServerProps
|
||||
from app.classes.minecraft.serverjars import server_jar_obj
|
||||
from app.classes.minecraft.stats import Stats
|
||||
from app.classes.shared.helpers import helper
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@ -45,7 +30,6 @@ class Roles_Controller:
|
||||
base_data = Roles_Controller.get_role_with_servers(role_id)
|
||||
up_data = {}
|
||||
added_servers = set()
|
||||
edited_servers = set()
|
||||
removed_servers = set()
|
||||
for key in role_data:
|
||||
if key == "role_id":
|
||||
@ -56,7 +40,7 @@ class Roles_Controller:
|
||||
elif base_data[key] != role_data[key]:
|
||||
up_data[key] = role_data[key]
|
||||
up_data['last_update'] = helper.get_time_as_string()
|
||||
logger.debug("role: {} +server:{} -server{}".format(role_data, added_servers, removed_servers))
|
||||
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)
|
||||
for server in base_data['servers']:
|
||||
|
@ -1,32 +1,20 @@
|
||||
import os
|
||||
import time
|
||||
import logging
|
||||
import sys
|
||||
import yaml
|
||||
import asyncio
|
||||
import shutil
|
||||
import tempfile
|
||||
import zipfile
|
||||
from distutils import dir_util
|
||||
|
||||
from app.classes.shared.helpers import helper
|
||||
from app.classes.shared.console import console
|
||||
|
||||
from app.classes.shared.main_models import db_helper
|
||||
from app.classes.models.server_permissions import server_permissions, Enum_Permissions_Server
|
||||
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.server import Server
|
||||
from app.classes.minecraft.server_props import ServerProps
|
||||
from app.classes.minecraft.serverjars import server_jar_obj
|
||||
from app.classes.minecraft.stats import Stats
|
||||
from app.classes.shared.main_models import db_helper
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class Server_Perms_Controller:
|
||||
|
||||
@staticmethod
|
||||
def get_server_user_list(server_id):
|
||||
return server_permissions.get_server_user_list(server_id)
|
||||
|
||||
@staticmethod
|
||||
def list_defined_permissions():
|
||||
permissions_list = server_permissions.get_permissions_list()
|
||||
@ -54,7 +42,9 @@ class Server_Perms_Controller:
|
||||
def backup_role_swap(old_server_id, new_server_id):
|
||||
role_list = server_permissions.get_server_roles(old_server_id)
|
||||
for role in role_list:
|
||||
server_permissions.add_role_server(new_server_id, role.role_id, server_permissions.get_permissions_mask(int(role.role_id), int(old_server_id)))
|
||||
server_permissions.add_role_server(
|
||||
new_server_id, role.role_id,
|
||||
server_permissions.get_permissions_mask(int(role.role_id), int(old_server_id)))
|
||||
#server_permissions.add_role_server(new_server_id, role.role_id, '00001000')
|
||||
|
||||
#************************************************************************************************
|
||||
@ -85,19 +75,6 @@ class Server_Perms_Controller:
|
||||
def get_api_key_permissions_list(key: ApiKeys, server_id: str):
|
||||
return server_permissions.get_api_key_permissions_list(key, server_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)
|
||||
|
||||
@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)
|
||||
|
||||
@staticmethod
|
||||
def get_api_key_permissions_list(key: ApiKeys, server_id: str):
|
||||
return server_permissions.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)
|
||||
|
@ -1,29 +1,15 @@
|
||||
from app.classes.controllers.roles_controller import Roles_Controller
|
||||
import os
|
||||
import time
|
||||
import logging
|
||||
import json
|
||||
import sys
|
||||
import yaml
|
||||
import asyncio
|
||||
import shutil
|
||||
import tempfile
|
||||
import zipfile
|
||||
from distutils import dir_util
|
||||
|
||||
from app.classes.shared.helpers import helper
|
||||
from app.classes.shared.console import console
|
||||
|
||||
from app.classes.shared.main_models import db_helper
|
||||
from app.classes.models.servers import servers_helper
|
||||
from app.classes.models.roles import roles_helper
|
||||
from app.classes.models.users import users_helper, ApiKeys
|
||||
from app.classes.models.server_permissions import server_permissions, Enum_Permissions_Server
|
||||
|
||||
from app.classes.shared.server import Server
|
||||
from app.classes.minecraft.server_props import ServerProps
|
||||
from app.classes.minecraft.serverjars import server_jar_obj
|
||||
from app.classes.minecraft.stats import Stats
|
||||
from app.classes.shared.helpers import helper
|
||||
from app.classes.shared.main_models import db_helper
|
||||
|
||||
from app.classes.controllers.roles_controller import Roles_Controller
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@ -33,8 +19,26 @@ class Servers_Controller:
|
||||
# Generic Servers Methods
|
||||
#************************************************************************************************
|
||||
@staticmethod
|
||||
def create_server(name: str, server_uuid: str, server_dir: str, backup_path: str, server_command: str, server_file: str, server_log_file: str, server_stop: str, server_port=25565):
|
||||
return servers_helper.create_server(name, server_uuid, server_dir, backup_path, server_command, server_file, server_log_file, server_stop, server_port)
|
||||
def create_server(
|
||||
name: str,
|
||||
server_uuid: str,
|
||||
server_dir: str,
|
||||
backup_path: str,
|
||||
server_command: str,
|
||||
server_file: str,
|
||||
server_log_file: str,
|
||||
server_stop: str,
|
||||
server_port=25565):
|
||||
return servers_helper.create_server(
|
||||
name,
|
||||
server_uuid,
|
||||
server_dir,
|
||||
backup_path,
|
||||
server_command,
|
||||
server_file,
|
||||
server_log_file,
|
||||
server_stop,
|
||||
server_port)
|
||||
|
||||
@staticmethod
|
||||
def get_server_obj(server_id):
|
||||
@ -183,7 +187,7 @@ class Servers_Controller:
|
||||
path = os.path.join(server_path, 'banned-players.json')
|
||||
|
||||
try:
|
||||
with open(helper.get_os_understandable_path(path)) as file:
|
||||
with open(helper.get_os_understandable_path(path), encoding='utf-8') as file:
|
||||
content = file.read()
|
||||
file.close()
|
||||
except Exception as ex:
|
||||
@ -210,4 +214,3 @@ class Servers_Controller:
|
||||
if helper.check_file_exists(log_file_path) and \
|
||||
helper.is_file_older_than_x_days(log_file_path, logs_delete_after):
|
||||
os.remove(log_file_path)
|
||||
|
||||
|
@ -1,23 +1,11 @@
|
||||
import os
|
||||
import time
|
||||
import logging
|
||||
import sys
|
||||
from typing import Optional
|
||||
|
||||
import yaml
|
||||
import asyncio
|
||||
import shutil
|
||||
import tempfile
|
||||
import zipfile
|
||||
from distutils import dir_util
|
||||
|
||||
from app.classes.shared.helpers import helper
|
||||
from app.classes.shared.console import console
|
||||
|
||||
from app.classes.models.users import Users, users_helper
|
||||
from app.classes.shared.authentication import authentication
|
||||
|
||||
from app.classes.models.users import users_helper
|
||||
from app.classes.models.crafty_permissions import crafty_permissions, Enum_Permissions_Crafty
|
||||
from app.classes.models.management import management_helper
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@ -60,7 +48,6 @@ class Users_Controller:
|
||||
up_data = {}
|
||||
added_roles = set()
|
||||
removed_roles = set()
|
||||
removed_servers = set()
|
||||
for key in user_data:
|
||||
if key == "user_id":
|
||||
continue
|
||||
@ -74,7 +61,7 @@ class Users_Controller:
|
||||
up_data[key] = user_data[key]
|
||||
up_data['last_update'] = helper.get_time_as_string()
|
||||
up_data['lang'] = user_data['lang']
|
||||
logger.debug("user: {} +role:{} -role:{}".format(user_data, added_roles, removed_roles))
|
||||
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')
|
||||
@ -90,7 +77,12 @@ class Users_Controller:
|
||||
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)
|
||||
crafty_permissions.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)
|
||||
|
||||
|
@ -1,11 +1,10 @@
|
||||
from app.classes.shared.helpers import Helpers
|
||||
import struct
|
||||
import socket
|
||||
import base64
|
||||
import json
|
||||
import sys
|
||||
import os
|
||||
import logging.config
|
||||
|
||||
from app.classes.shared.console import console
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@ -101,13 +100,13 @@ def get_code_format(format_name):
|
||||
if format_name in data.keys():
|
||||
return data.get(format_name)
|
||||
else:
|
||||
logger.error("Format MOTD Error: format name {} does not exist".format(format_name))
|
||||
console.error("Format MOTD Error: format name {} does not exist".format(format_name))
|
||||
logger.error(f"Format MOTD Error: format name {format_name} does not exist")
|
||||
console.error(f"Format MOTD Error: format name {format_name} does not exist")
|
||||
return ""
|
||||
|
||||
except Exception as e:
|
||||
logger.critical("Config File Error: Unable to read {} due to {}".format(format_file, e))
|
||||
console.critical("Config File Error: Unable to read {} due to {}".format(format_file, 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}")
|
||||
|
||||
return ""
|
||||
|
||||
@ -126,15 +125,14 @@ def ping(ip, port):
|
||||
j += 1
|
||||
if j > 5:
|
||||
raise ValueError('var_int too big')
|
||||
if not (k & 0x80):
|
||||
if not k & 0x80:
|
||||
return i
|
||||
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
try:
|
||||
sock.connect((ip, port))
|
||||
|
||||
except socket.error as err:
|
||||
pass
|
||||
except socket.error:
|
||||
return False
|
||||
|
||||
try:
|
||||
@ -163,7 +161,7 @@ def ping(ip, port):
|
||||
return False
|
||||
|
||||
data += chunk
|
||||
logger.debug("Server reports this data on ping: {}".format(data))
|
||||
logger.debug(f"Server reports this data on ping: {data}")
|
||||
return Server(json.loads(data))
|
||||
finally:
|
||||
sock.close()
|
||||
|
@ -9,7 +9,7 @@ class ServerProps:
|
||||
|
||||
def _parse(self):
|
||||
"""Loads and parses the file specified in self.filepath"""
|
||||
with open(self.filepath) as fp:
|
||||
with open(self.filepath, encoding='utf-8') as fp:
|
||||
line = fp.readline()
|
||||
d = {}
|
||||
if os.path.exists(".header"):
|
||||
@ -24,7 +24,7 @@ class ServerProps:
|
||||
s2 = s[s.find('=')+1:]
|
||||
d[s1] = s2
|
||||
else:
|
||||
with open(".header", "a+") as h:
|
||||
with open(".header", "a+", encoding='utf-8') as h:
|
||||
h.write(line)
|
||||
line = fp.readline()
|
||||
return d
|
||||
@ -47,9 +47,9 @@ class ServerProps:
|
||||
|
||||
def save(self):
|
||||
"""Writes to the new file"""
|
||||
with open(self.filepath, "a+") as f:
|
||||
with open(self.filepath, "a+", encoding='utf-8') as f:
|
||||
f.truncate(0)
|
||||
with open(".header") as header:
|
||||
with open(".header", encoding='utf-8') as header:
|
||||
line = header.readline()
|
||||
while line:
|
||||
f.write(line)
|
||||
|
@ -1,4 +1,3 @@
|
||||
import os
|
||||
import sys
|
||||
import json
|
||||
import threading
|
||||
@ -9,19 +8,15 @@ from datetime import datetime
|
||||
|
||||
from app.classes.shared.helpers import helper
|
||||
from app.classes.shared.console import console
|
||||
from app.classes.models.servers import Servers
|
||||
from app.classes.minecraft.server_props import ServerProps
|
||||
from app.classes.web.websocket_helper import websocket_helper
|
||||
from app.classes.models.server_permissions import server_permissions
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
try:
|
||||
import requests
|
||||
|
||||
except ModuleNotFoundError as e:
|
||||
logger.critical("Import Error: Unable to load {} module".format(e.name), exc_info=True)
|
||||
console.critical("Import Error: Unable to load {} module".format(e.name))
|
||||
except ModuleNotFoundError as err:
|
||||
logger.critical(f"Import Error: Unable to load {err.name} module", exc_info=True)
|
||||
console.critical(f"Import Error: Unable to load {err.name} module")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
@ -31,7 +26,7 @@ class ServerJars:
|
||||
self.base_url = "https://serverjars.com"
|
||||
|
||||
def _get_api_result(self, call_url: str):
|
||||
full_url = "{base}{call_url}".format(base=self.base_url, call_url=call_url)
|
||||
full_url = f"{self.base_url}{call_url}"
|
||||
|
||||
try:
|
||||
r = requests.get(full_url, timeout=2)
|
||||
@ -39,20 +34,20 @@ class ServerJars:
|
||||
if r.status_code not in [200, 201]:
|
||||
return {}
|
||||
except Exception as e:
|
||||
logger.error("Unable to connect to serverjar.com api due to error: {}".format(e))
|
||||
logger.error(f"Unable to connect to serverjar.com api due to error: {e}")
|
||||
return {}
|
||||
|
||||
try:
|
||||
api_data = json.loads(r.content)
|
||||
except Exception as e:
|
||||
logger.error("Unable to parse serverjar.com api result due to error: {}".format(e))
|
||||
logger.error(f"Unable to parse serverjar.com api result due to error: {e}")
|
||||
return {}
|
||||
|
||||
api_result = api_data.get('status')
|
||||
api_response = api_data.get('response', {})
|
||||
|
||||
if api_result != "success":
|
||||
logger.error("Api returned a failed status: {}".format(api_result))
|
||||
logger.error(f"Api returned a failed status: {api_result}")
|
||||
return {}
|
||||
|
||||
return api_response
|
||||
@ -62,11 +57,11 @@ class ServerJars:
|
||||
cache_file = helper.serverjar_cache
|
||||
cache = {}
|
||||
try:
|
||||
with open(cache_file, "r") as f:
|
||||
with open(cache_file, "r", encoding='utf-8') as f:
|
||||
cache = json.load(f)
|
||||
|
||||
except Exception as e:
|
||||
logger.error("Unable to read serverjars.com cache file: {}".format(e))
|
||||
logger.error(f"Unable to read serverjars.com cache file: {e}")
|
||||
|
||||
return cache
|
||||
|
||||
@ -100,7 +95,7 @@ class ServerJars:
|
||||
def _check_api_alive(self):
|
||||
logger.info("Checking serverjars.com API status")
|
||||
|
||||
check_url = "{base}/api/fetchTypes".format(base=self.base_url)
|
||||
check_url = f"{self.base_url}/api/fetchTypes"
|
||||
try:
|
||||
r = requests.get(check_url, timeout=2)
|
||||
|
||||
@ -108,7 +103,7 @@ class ServerJars:
|
||||
logger.info("Serverjars.com API is alive")
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error("Unable to connect to serverjar.com api due to error: {}".format(e))
|
||||
logger.error(f"Unable to connect to serverjar.com api due to error: {e}")
|
||||
return {}
|
||||
|
||||
logger.error("unable to contact serverjars.com api")
|
||||
@ -154,15 +149,15 @@ class ServerJars:
|
||||
|
||||
# save our cache
|
||||
try:
|
||||
with open(cache_file, "w") as f:
|
||||
with open(cache_file, "w", encoding='utf-8') as f:
|
||||
f.write(json.dumps(data, indent=4))
|
||||
logger.info("Cache file refreshed")
|
||||
|
||||
except Exception as e:
|
||||
logger.error("Unable to update serverjars.com cache file: {}".format(e))
|
||||
logger.error(f"Unable to update serverjars.com cache file: {e}")
|
||||
|
||||
def _get_jar_details(self, jar_type='servers'):
|
||||
url = '/api/fetchAll/{type}'.format(type=jar_type)
|
||||
url = f'/api/fetchAll/{jar_type}'
|
||||
response = self._get_api_result(url)
|
||||
temp = []
|
||||
for v in response:
|
||||
@ -175,12 +170,12 @@ class ServerJars:
|
||||
response = self._get_api_result(url)
|
||||
return response
|
||||
|
||||
def download_jar(self, server, version, path, name):
|
||||
update_thread = threading.Thread(target=self.a_download_jar, daemon=True, name="exe_download", args=(server, version, path, name))
|
||||
def download_jar(self, server, version, path):
|
||||
update_thread = threading.Thread(target=self.a_download_jar, daemon=True, args=(server, version, path))
|
||||
update_thread.start()
|
||||
|
||||
def a_download_jar(self, server, version, path, name):
|
||||
fetch_url = "{base}/api/fetchJar/{server}/{version}".format(base=self.base_url, server=server, version=version)
|
||||
def a_download_jar(self, server, version, path):
|
||||
fetch_url = f"{self.base_url}/api/fetchJar/{server}/{version}"
|
||||
|
||||
# open a file stream
|
||||
with requests.get(fetch_url, timeout=2, stream=True) as r:
|
||||
@ -189,9 +184,7 @@ class ServerJars:
|
||||
shutil.copyfileobj(r.raw, output)
|
||||
|
||||
except Exception as e:
|
||||
logger.error("Unable to save jar to {path} due to error:{error}".format(path=path, error=e))
|
||||
pass
|
||||
|
||||
logger.error(f"Unable to save jar to {path} due to error:{e}")
|
||||
|
||||
return False
|
||||
|
||||
|
@ -1,16 +1,15 @@
|
||||
import os
|
||||
import json
|
||||
import time
|
||||
import psutil
|
||||
import logging
|
||||
import datetime
|
||||
import base64
|
||||
import psutil
|
||||
|
||||
from app.classes.models.management import Host_Stats
|
||||
from app.classes.models.servers import Server_Stats, servers_helper
|
||||
|
||||
from app.classes.shared.helpers import helper
|
||||
from app.classes.minecraft.mc_ping import ping
|
||||
from app.classes.models.management import Host_Stats
|
||||
from app.classes.models.servers import Server_Stats, servers_helper
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@ -64,8 +63,6 @@ class Stats:
|
||||
|
||||
real_cpu = round(p.cpu_percent(interval=0.5) / psutil.cpu_count(), 2)
|
||||
|
||||
process_start_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(p.create_time()))
|
||||
|
||||
# this is a faster way of getting data for a process
|
||||
with p.oneshot():
|
||||
process_stats = {
|
||||
@ -76,7 +73,7 @@ class Stats:
|
||||
return process_stats
|
||||
|
||||
except Exception as e:
|
||||
logger.error("Unable to get process details for pid: {} due to error: {}".format(process_pid, e))
|
||||
logger.error(f"Unable to get process details for pid: {process_pid} due to error: {e}")
|
||||
|
||||
# Dummy Data
|
||||
process_stats = {
|
||||
@ -119,13 +116,13 @@ class Stats:
|
||||
total_size = 0
|
||||
|
||||
# do a scan of the directories in the server path.
|
||||
for root, dirs, files in os.walk(world_path, topdown=False):
|
||||
for root, dirs, _files in os.walk(world_path, topdown=False):
|
||||
|
||||
# for each directory we find
|
||||
for name in dirs:
|
||||
|
||||
# if the directory name is "region"
|
||||
if name == "region":
|
||||
if str(name) == "region":
|
||||
# log it!
|
||||
logger.debug("Path %s is called region. Getting directory size", os.path.join(root, name))
|
||||
|
||||
@ -144,14 +141,14 @@ class Stats:
|
||||
online_stats = json.loads(ping_obj.players)
|
||||
|
||||
except Exception as e:
|
||||
logger.info("Unable to read json from ping_obj: {}".format(e))
|
||||
pass
|
||||
logger.info(f"Unable to read json from ping_obj: {e}")
|
||||
|
||||
|
||||
try:
|
||||
server_icon = base64.encodebytes(ping_obj.icon)
|
||||
except Exception as e:
|
||||
server_icon = False
|
||||
logger.info("Unable to read the server icon : {}".format(e))
|
||||
logger.info(f"Unable to read the server icon : {e}")
|
||||
|
||||
ping_data = {
|
||||
'online': online_stats.get("online", 0),
|
||||
@ -168,18 +165,18 @@ class Stats:
|
||||
|
||||
server = servers_helper.get_server_data_by_id(server_id)
|
||||
|
||||
logger.info("Getting players for server {}".format(server))
|
||||
logger.info(f"Getting players for server {server}")
|
||||
|
||||
# get our settings and data dictionaries
|
||||
server_settings = server.get('server_settings', {})
|
||||
server_data = server.get('server_data_obj', {})
|
||||
# server_settings = server.get('server_settings', {})
|
||||
# server_data = server.get('server_data_obj', {})
|
||||
|
||||
|
||||
# TODO: search server properties file for possible override of 127.0.0.1
|
||||
internal_ip = server['server_ip']
|
||||
server_port = server['server_port']
|
||||
|
||||
logger.debug("Pinging {} on port {}".format(internal_ip, server_port))
|
||||
logger.debug("Pinging {internal_ip} on port {server_port}")
|
||||
int_mc_ping = ping(internal_ip, int(server_port))
|
||||
|
||||
ping_data = {}
|
||||
@ -205,7 +202,7 @@ class Stats:
|
||||
server = servers_helper.get_server_data_by_id(server_id)
|
||||
|
||||
|
||||
logger.debug('Getting stats for server: {}'.format(server_id))
|
||||
logger.debug(f'Getting stats for server: {server_id}')
|
||||
|
||||
# get our server object, settings and data dictionaries
|
||||
server_obj = s.get('server_obj', None)
|
||||
@ -223,8 +220,9 @@ class Stats:
|
||||
# TODO: search server properties file for possible override of 127.0.0.1
|
||||
internal_ip = server['server_ip']
|
||||
server_port = server['server_port']
|
||||
server = s.get('server_name', f"ID#{server_id}")
|
||||
|
||||
logger.debug("Pinging server '{}' on {}:{}".format(s.get('server_name', "ID#{}".format(server_id)), internal_ip, server_port))
|
||||
logger.debug("Pinging server '{server}' on {internal_ip}:{server_port}")
|
||||
int_mc_ping = ping(internal_ip, int(server_port))
|
||||
|
||||
int_data = False
|
||||
@ -263,7 +261,7 @@ class Stats:
|
||||
server_stats = {}
|
||||
server = self.controller.get_server_obj(server_id)
|
||||
|
||||
logger.debug('Getting stats for server: {}'.format(server_id))
|
||||
logger.debug(f'Getting stats for server: {server_id}')
|
||||
|
||||
# get our server object, settings and data dictionaries
|
||||
server_obj = self.controller.get_server_obj(server_id)
|
||||
@ -285,7 +283,7 @@ class Stats:
|
||||
server_port = server_settings.get('server-port', "25565")
|
||||
|
||||
|
||||
logger.debug("Pinging server '{}' on {}:{}".format(server.name, internal_ip, server_port))
|
||||
logger.debug(f"Pinging server '{server.name}' on {internal_ip}:{server_port}")
|
||||
int_mc_ping = ping(internal_ip, int(server_port))
|
||||
|
||||
int_data = False
|
||||
|
@ -1,26 +1,23 @@
|
||||
import os
|
||||
import sys
|
||||
import logging
|
||||
import datetime
|
||||
|
||||
from app.classes.shared.helpers import helper
|
||||
from app.classes.shared.console import console
|
||||
from app.classes.models.users import Users, ApiKeys
|
||||
from app.classes.shared.permission_helper import permission_helper
|
||||
|
||||
from app.classes.models.users import Users, ApiKeys
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
peewee_logger = logging.getLogger('peewee')
|
||||
peewee_logger.setLevel(logging.INFO)
|
||||
|
||||
try:
|
||||
from peewee import *
|
||||
from playhouse.shortcuts import model_to_dict
|
||||
from peewee import SqliteDatabase, Model, ForeignKeyField, CharField, IntegerField, DoesNotExist
|
||||
from enum import Enum
|
||||
import yaml
|
||||
|
||||
except ModuleNotFoundError as e:
|
||||
logger.critical("Import Error: Unable to load {} module".format(e.name), exc_info=True)
|
||||
console.critical("Import Error: Unable to load {} module".format(e.name))
|
||||
logger.critical(f"Import Error: Unable to load {e.name} module", exc_info=True)
|
||||
console.critical(f"Import Error: Unable to load {e.name} module")
|
||||
sys.exit(1)
|
||||
|
||||
database = SqliteDatabase(helper.db_path, pragmas={
|
||||
@ -124,7 +121,7 @@ class Permissions_Crafty:
|
||||
def get_User_Crafty(user_id):
|
||||
try:
|
||||
user_crafty = User_Crafty.select().where(User_Crafty.user_id == user_id).get()
|
||||
except User_Crafty.DoesNotExist:
|
||||
except DoesNotExist:
|
||||
user_crafty = User_Crafty.insert({
|
||||
User_Crafty.user_id: user_id,
|
||||
User_Crafty.permissions: "000",
|
||||
@ -173,7 +170,6 @@ class Permissions_Crafty:
|
||||
|
||||
@staticmethod
|
||||
def get_crafty_limit_value(user_id, permission):
|
||||
user_crafty = crafty_permissions.get_User_Crafty(user_id)
|
||||
quantity_list = crafty_permissions.get_permission_quantity_list(user_id)
|
||||
return quantity_list[permission]
|
||||
|
||||
|
@ -1,4 +1,3 @@
|
||||
import os
|
||||
import sys
|
||||
import logging
|
||||
import datetime
|
||||
@ -6,26 +5,24 @@ import datetime
|
||||
from app.classes.shared.helpers import helper
|
||||
from app.classes.shared.console import console
|
||||
from app.classes.shared.main_models import db_helper
|
||||
from app.classes.models.users import Users, users_helper
|
||||
from app.classes.models.servers import Servers, servers_helper
|
||||
from app.classes.web.websocket_helper import websocket_helper
|
||||
from app.classes.models.server_permissions import server_permissions
|
||||
import time
|
||||
|
||||
from app.classes.models.users import Users, users_helper
|
||||
from app.classes.models.servers import Servers
|
||||
from app.classes.models.server_permissions import server_permissions
|
||||
|
||||
from app.classes.web.websocket_helper import websocket_helper
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
peewee_logger = logging.getLogger('peewee')
|
||||
peewee_logger.setLevel(logging.INFO)
|
||||
|
||||
try:
|
||||
from peewee import *
|
||||
from peewee import SqliteDatabase, Model, ForeignKeyField, CharField, IntegerField, DateTimeField, FloatField, TextField, AutoField, BooleanField
|
||||
from playhouse.shortcuts import model_to_dict
|
||||
from enum import Enum
|
||||
import yaml
|
||||
|
||||
except ModuleNotFoundError as e:
|
||||
logger.critical("Import Error: Unable to load {} module".format(e.name), exc_info=True)
|
||||
console.critical("Import Error: Unable to load {} module".format(e.name))
|
||||
logger.critical(f"Import Error: Unable to load {e.name} module", exc_info=True)
|
||||
console.critical(f"Import Error: Unable to load {e.name} module")
|
||||
sys.exit(1)
|
||||
|
||||
database = SqliteDatabase(helper.db_path, pragmas={
|
||||
@ -140,7 +137,7 @@ class helpers_management:
|
||||
#************************************************************************************************
|
||||
@staticmethod
|
||||
def get_latest_hosts_stats():
|
||||
query = Host_Stats.select().order_by(Host_Stats.id.desc()).get()
|
||||
query = Host_Stats.select().order_by(Host_Stats).get()
|
||||
return model_to_dict(query)
|
||||
|
||||
#************************************************************************************************
|
||||
@ -163,7 +160,7 @@ class helpers_management:
|
||||
@staticmethod
|
||||
def mark_command_complete(command_id=None):
|
||||
if command_id is not None:
|
||||
logger.debug("Marking Command {} completed".format(command_id))
|
||||
logger.debug(f"Marking Command {command_id} completed")
|
||||
Commands.update({
|
||||
Commands.executed: True
|
||||
}).where(Commands.command_id == command_id).execute()
|
||||
@ -178,10 +175,10 @@ class helpers_management:
|
||||
|
||||
@staticmethod
|
||||
def add_to_audit_log(user_id, log_msg, server_id=None, source_ip=None):
|
||||
logger.debug("Adding to audit log User:{} - Message: {} ".format(user_id, log_msg))
|
||||
logger.debug(f"Adding to audit log User:{user_id} - Message: {log_msg} ")
|
||||
user_data = users_helper.get_user(user_id)
|
||||
|
||||
audit_msg = "{} {}".format(str(user_data['username']).capitalize(), log_msg)
|
||||
audit_msg = f"{str(user_data['username']).capitalize()} {log_msg}"
|
||||
|
||||
server_users = server_permissions.get_server_user_list(server_id)
|
||||
for user in server_users:
|
||||
@ -209,7 +206,17 @@ class helpers_management:
|
||||
# Schedules Methods
|
||||
#************************************************************************************************
|
||||
@staticmethod
|
||||
def create_scheduled_task(server_id, action, interval, interval_type, start_time, command, comment=None, enabled=True, one_time=False, cron_string='* * * * *'):
|
||||
def create_scheduled_task(
|
||||
server_id,
|
||||
action,
|
||||
interval,
|
||||
interval_type,
|
||||
start_time,
|
||||
command,
|
||||
comment=None,
|
||||
enabled=True,
|
||||
one_time=False,
|
||||
cron_string='* * * * *'):
|
||||
sch_id = Schedules.insert({
|
||||
Schedules.server_id: server_id,
|
||||
Schedules.action: action,
|
||||
@ -240,7 +247,7 @@ class helpers_management:
|
||||
|
||||
@staticmethod
|
||||
def get_scheduled_task(schedule_id):
|
||||
return model_to_dict(Schedules.get(Schedules.schedule_id == schedule_id)).execute()
|
||||
return model_to_dict(Schedules.get(Schedules.schedule_id == schedule_id))
|
||||
|
||||
@staticmethod
|
||||
def get_scheduled_task_model(schedule_id):
|
||||
@ -256,7 +263,7 @@ class helpers_management:
|
||||
|
||||
@staticmethod
|
||||
def get_schedules_enabled():
|
||||
return Schedules.select().where(Schedules.enabled == True).execute()
|
||||
return Schedules.select().where(Schedules.enabled is True).execute()
|
||||
|
||||
#************************************************************************************************
|
||||
# Backups Methods
|
||||
@ -282,12 +289,10 @@ class helpers_management:
|
||||
|
||||
@staticmethod
|
||||
def set_backup_config(server_id: int, backup_path: str = None, max_backups: int = None):
|
||||
logger.debug("Updating server {} backup config with {}".format(server_id, locals()))
|
||||
logger.debug(f"Updating server {server_id} backup config with {locals()}")
|
||||
try:
|
||||
row = Backups.select().where(Backups.server_id == server_id).join(Servers)[0]
|
||||
new_row = False
|
||||
conf = {}
|
||||
schd = {}
|
||||
except IndexError:
|
||||
conf = {
|
||||
"directories": None,
|
||||
@ -304,13 +309,13 @@ class helpers_management:
|
||||
else:
|
||||
u1 = 0
|
||||
u2 = Backups.update(conf).where(Backups.server_id == server_id).execute()
|
||||
logger.debug("Updating existing backup record. {}+{} rows affected".format(u1, u2))
|
||||
logger.debug(f"Updating existing backup record. {u1}+{u2} rows affected")
|
||||
else:
|
||||
with database.atomic():
|
||||
conf["server_id"] = server_id
|
||||
if backup_path is not None:
|
||||
u = Servers.update(backup_path=backup_path).where(Servers.server_id == server_id)
|
||||
b = Backups.create(**conf)
|
||||
Servers.update(backup_path=backup_path).where(Servers.server_id == server_id)
|
||||
Backups.create(**conf)
|
||||
logger.debug("Creating new backup record.")
|
||||
|
||||
|
||||
|
@ -1,4 +1,3 @@
|
||||
import os
|
||||
import sys
|
||||
import logging
|
||||
import datetime
|
||||
@ -11,14 +10,12 @@ peewee_logger = logging.getLogger('peewee')
|
||||
peewee_logger.setLevel(logging.INFO)
|
||||
|
||||
try:
|
||||
from peewee import *
|
||||
from peewee import SqliteDatabase, Model, CharField, DoesNotExist, AutoField, DateTimeField
|
||||
from playhouse.shortcuts import model_to_dict
|
||||
from enum import Enum
|
||||
import yaml
|
||||
|
||||
except ModuleNotFoundError as e:
|
||||
logger.critical("Import Error: Unable to load {} module".format(e.name), exc_info=True)
|
||||
console.critical("Import Error: Unable to load {} module".format(e.name))
|
||||
logger.critical(f"Import Error: Unable to load {e.name} module", exc_info=True)
|
||||
console.critical(f"Import Error: Unable to load {e.name} module")
|
||||
sys.exit(1)
|
||||
|
||||
database = SqliteDatabase(helper.db_path, pragmas={
|
||||
|
@ -1,28 +1,26 @@
|
||||
import os
|
||||
import sys
|
||||
import logging
|
||||
import datetime
|
||||
|
||||
from app.classes.shared.helpers import helper
|
||||
from app.classes.shared.console import console
|
||||
from app.classes.shared.permission_helper import permission_helper
|
||||
|
||||
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.permission_helper import permission_helper
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
peewee_logger = logging.getLogger('peewee')
|
||||
peewee_logger.setLevel(logging.INFO)
|
||||
|
||||
try:
|
||||
from peewee import *
|
||||
from playhouse.shortcuts import model_to_dict
|
||||
from peewee import SqliteDatabase, Model, ForeignKeyField, CharField, CompositeKey, JOIN
|
||||
from enum import Enum
|
||||
import yaml
|
||||
|
||||
except ModuleNotFoundError as e:
|
||||
logger.critical("Import Error: Unable to load {} module".format(e.name), exc_info=True)
|
||||
console.critical("Import Error: Unable to load {} module".format(e.name))
|
||||
logger.critical(f"Import Error: Unable to load {e.name} module", exc_info=True)
|
||||
console.critical(f"Import Error: Unable to load {e.name} module")
|
||||
sys.exit(1)
|
||||
|
||||
database = SqliteDatabase(helper.db_path, pragmas={
|
||||
@ -118,7 +116,8 @@ class Permissions_Servers:
|
||||
|
||||
@staticmethod
|
||||
def add_role_server(server_id, role_id, rs_permissions="00000000"):
|
||||
servers = Role_Servers.insert({Role_Servers.server_id: server_id, Role_Servers.role_id: role_id, Role_Servers.permissions: rs_permissions}).execute()
|
||||
servers = Role_Servers.insert({Role_Servers.server_id: server_id, Role_Servers.role_id: role_id,
|
||||
Role_Servers.permissions: rs_permissions}).execute()
|
||||
return servers
|
||||
|
||||
@staticmethod
|
||||
@ -181,6 +180,7 @@ class Permissions_Servers:
|
||||
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)
|
||||
for role in server_roles:
|
||||
users = User_Roles.select().where(User_Roles.role_id == role.role_id)
|
||||
|
@ -1,11 +1,9 @@
|
||||
import os
|
||||
import sys
|
||||
import logging
|
||||
import datetime
|
||||
|
||||
from app.classes.shared.helpers import helper
|
||||
from app.classes.shared.console import console
|
||||
|
||||
from app.classes.shared.main_models import db_helper
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@ -13,14 +11,11 @@ peewee_logger = logging.getLogger('peewee')
|
||||
peewee_logger.setLevel(logging.INFO)
|
||||
|
||||
try:
|
||||
from peewee import *
|
||||
from playhouse.shortcuts import model_to_dict
|
||||
from enum import Enum
|
||||
import yaml
|
||||
from peewee import SqliteDatabase, Model, ForeignKeyField, CharField, AutoField, DateTimeField, BooleanField, IntegerField, FloatField
|
||||
|
||||
except ModuleNotFoundError as e:
|
||||
logger.critical("Import Error: Unable to load {} module".format(e.name), exc_info=True)
|
||||
console.critical("Import Error: Unable to load {} module".format(e.name))
|
||||
logger.critical(f"Import Error: Unable to load {e.name} module", exc_info=True)
|
||||
console.critical(f"Import Error: Unable to load {e.name} module")
|
||||
sys.exit(1)
|
||||
|
||||
database = SqliteDatabase(helper.db_path, pragmas={
|
||||
@ -94,7 +89,16 @@ class helper_servers:
|
||||
# Generic Servers Methods
|
||||
#************************************************************************************************
|
||||
@staticmethod
|
||||
def create_server(name: str, server_uuid: str, server_dir: str, backup_path: str, server_command: str, server_file: str, server_log_file: str, server_stop: str, server_port=25565):
|
||||
def create_server(
|
||||
name: str,
|
||||
server_uuid: str,
|
||||
server_dir: str,
|
||||
backup_path: str,
|
||||
server_command: str,
|
||||
server_file: str,
|
||||
server_log_file: str,
|
||||
server_stop: str,
|
||||
server_port=25565):
|
||||
return Servers.insert({
|
||||
Servers.server_name: name,
|
||||
Servers.server_uuid: server_uuid,
|
||||
@ -153,7 +157,7 @@ class helper_servers:
|
||||
@staticmethod
|
||||
def get_server_friendly_name(server_id):
|
||||
server_data = servers_helper.get_server_data_by_id(server_id)
|
||||
friendly_name = "{} with ID: {}".format(server_data.get('server_name', None), server_data.get('server_id', 0))
|
||||
friendly_name = f"{server_data.get('server_name', None)} with ID: {server_data.get('server_id', 0)}"
|
||||
return friendly_name
|
||||
|
||||
#************************************************************************************************
|
||||
@ -177,9 +181,10 @@ class helper_servers:
|
||||
@staticmethod
|
||||
def set_update(server_id, value):
|
||||
try:
|
||||
row = Server_Stats.select().where(Server_Stats.server_id == server_id)
|
||||
#Checks if server even exists
|
||||
Server_Stats.select().where(Server_Stats.server_id == server_id)
|
||||
except Exception as ex:
|
||||
logger.error("Database entry not found. ".format(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()
|
||||
|
||||
@ -192,9 +197,11 @@ class helper_servers:
|
||||
def set_first_run(server_id):
|
||||
#Sets first run to false
|
||||
try:
|
||||
row = Server_Stats.select().where(Server_Stats.server_id == server_id)
|
||||
#Checks if server even exists
|
||||
Server_Stats.select().where(Server_Stats.server_id == server_id)
|
||||
except Exception as ex:
|
||||
logger.error("Database entry not found. ".format(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()
|
||||
|
||||
@ -206,7 +213,12 @@ class helper_servers:
|
||||
@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()
|
||||
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
|
||||
@ -220,9 +232,10 @@ class helper_servers:
|
||||
@staticmethod
|
||||
def set_waiting_start(server_id, value):
|
||||
try:
|
||||
row = Server_Stats.select().where(Server_Stats.server_id == server_id)
|
||||
# Checks if server even exists
|
||||
Server_Stats.select().where(Server_Stats.server_id == server_id)
|
||||
except Exception as ex:
|
||||
logger.error("Database entry not found. ".format(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()
|
||||
|
||||
|
@ -1,8 +1,7 @@
|
||||
import os
|
||||
import sys
|
||||
import logging
|
||||
import datetime
|
||||
from typing import Optional, List, Union
|
||||
from typing import Optional, Union
|
||||
|
||||
from app.classes.shared.helpers import helper
|
||||
from app.classes.shared.console import console
|
||||
@ -14,14 +13,12 @@ peewee_logger = logging.getLogger('peewee')
|
||||
peewee_logger.setLevel(logging.INFO)
|
||||
|
||||
try:
|
||||
from peewee import *
|
||||
from peewee import SqliteDatabase, Model, ForeignKeyField, CharField, AutoField, DateTimeField, BooleanField, CompositeKey, DoesNotExist, JOIN
|
||||
from playhouse.shortcuts import model_to_dict
|
||||
from enum import Enum
|
||||
import yaml
|
||||
|
||||
except ModuleNotFoundError as e:
|
||||
logger.critical("Import Error: Unable to load {} module".format(e.name), exc_info=True)
|
||||
console.critical("Import Error: Unable to load {} module".format(e.name))
|
||||
logger.critical(f"Import Error: Unable to load {e.name} module", exc_info=True)
|
||||
console.critical(f"Import Error: Unable to load {e.name} module")
|
||||
sys.exit(1)
|
||||
|
||||
database = SqliteDatabase(helper.db_path, pragmas={
|
||||
@ -58,7 +55,7 @@ class ApiKeys(Model):
|
||||
token_id = AutoField()
|
||||
name = CharField(default='', unique=True, index=True)
|
||||
created = DateTimeField(default=datetime.datetime.now)
|
||||
user = ForeignKeyField(Users, backref='api_token', index=True)
|
||||
user_id = ForeignKeyField(Users, backref='api_token', index=True)
|
||||
server_permissions = CharField(default='00000000')
|
||||
crafty_permissions = CharField(default='000')
|
||||
superuser = BooleanField(default=False)
|
||||
@ -138,9 +135,11 @@ class helper_users:
|
||||
#logger.debug("user: ({}) {}".format(user_id, {}))
|
||||
return {}
|
||||
|
||||
@staticmethod
|
||||
def check_system_user(user_id):
|
||||
try:
|
||||
Users.get(Users.user_id == user_id).user_id == user_id
|
||||
result = Users.get(Users.user_id == user_id).user_id == user_id
|
||||
if result:
|
||||
return True
|
||||
except:
|
||||
return False
|
||||
@ -177,6 +176,7 @@ class helper_users:
|
||||
@staticmethod
|
||||
def get_super_user_list():
|
||||
final_users = []
|
||||
# pylint: disable=singleton-comparison
|
||||
super_users = Users.select().where(Users.superuser == True)
|
||||
for suser in super_users:
|
||||
if suser.user_id not in final_users:
|
||||
@ -233,7 +233,7 @@ class helper_users:
|
||||
|
||||
@staticmethod
|
||||
def add_user_roles(user: Union[dict, Users]):
|
||||
if type(user) == dict:
|
||||
if isinstance(user, dict):
|
||||
user_id = user['user_id']
|
||||
else:
|
||||
user_id = user.user_id
|
||||
@ -246,7 +246,7 @@ class helper_users:
|
||||
for r in roles_query:
|
||||
roles.add(r.role_id.role_id)
|
||||
|
||||
if type(user) == dict:
|
||||
if isinstance(user, dict):
|
||||
user['roles'] = roles
|
||||
else:
|
||||
user.roles = roles
|
||||
@ -283,7 +283,12 @@ class helper_users:
|
||||
return ApiKeys.get(ApiKeys.token_id == key_id)
|
||||
|
||||
@staticmethod
|
||||
def add_user_api_key(name: str, user_id: str, superuser: bool = False, server_permissions_mask: Optional[str] = None, crafty_permissions_mask: Optional[str] = None):
|
||||
def add_user_api_key(
|
||||
name: str,
|
||||
user_id: str,
|
||||
superuser: bool = False,
|
||||
server_permissions_mask: Optional[str] = None,
|
||||
crafty_permissions_mask: Optional[str] = None):
|
||||
return ApiKeys.insert({
|
||||
ApiKeys.name: name,
|
||||
ApiKeys.user_id: user_id,
|
||||
|
@ -1,28 +1,16 @@
|
||||
import os
|
||||
import sys
|
||||
import cmd
|
||||
import time
|
||||
import threading
|
||||
import logging
|
||||
|
||||
from app.classes.shared.tasks import TasksManager
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
from app.classes.shared.console import console
|
||||
from app.classes.shared.helpers import helper
|
||||
|
||||
from app.classes.web.websocket_helper import websocket_helper
|
||||
|
||||
try:
|
||||
import requests
|
||||
|
||||
except ModuleNotFoundError as e:
|
||||
logger.critical("Import Error: Unable to load {} module".format(e.name), exc_info=True)
|
||||
console.critical("Import Error: Unable to load {} module".format(e.name))
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
class MainPrompt(cmd.Cmd, object):
|
||||
logger = logging.getLogger(__name__)
|
||||
class MainPrompt(cmd.Cmd):
|
||||
|
||||
def __init__(self, tasks_manager, migration_manager):
|
||||
super().__init__()
|
||||
@ -30,12 +18,13 @@ class MainPrompt(cmd.Cmd, object):
|
||||
self.migration_manager = migration_manager
|
||||
|
||||
# overrides the default Prompt
|
||||
prompt = "Crafty Controller v{} > ".format(helper.get_version_string())
|
||||
prompt = f"Crafty Controller v{helper.get_version_string()} > "
|
||||
|
||||
@staticmethod
|
||||
def emptyline():
|
||||
pass
|
||||
|
||||
#pylint: disable=unused-argument
|
||||
def do_exit(self, line):
|
||||
self.tasks_manager._main_graceful_exit()
|
||||
self.universal_exit()
|
||||
@ -52,9 +41,9 @@ class MainPrompt(cmd.Cmd, object):
|
||||
elif line == 'diff':
|
||||
console.info(self.migration_manager.diff)
|
||||
elif line == 'info':
|
||||
console.info('Done: {}'.format(self.migration_manager.done))
|
||||
console.info('FS: {}'.format(self.migration_manager.todo))
|
||||
console.info('Todo: {}'.format(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)
|
@ -9,13 +9,12 @@ try:
|
||||
from termcolor import colored
|
||||
|
||||
except ModuleNotFoundError as e:
|
||||
logger.critical("Import Error: Unable to load {} module".format(e.name), exc_info=True)
|
||||
print("Import Error: Unable to load {} module".format(e.name))
|
||||
logger.critical(f"Import Error: Unable to load {e.name} module", exc_info=True)
|
||||
print(f"Import Error: Unable to load {e.name} module")
|
||||
from app.classes.shared.installer import installer
|
||||
installer.do_install()
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
class Console:
|
||||
|
||||
def __init__(self):
|
||||
@ -49,28 +48,27 @@ class Console:
|
||||
|
||||
def debug(self, message):
|
||||
dt = datetime.datetime.now().strftime("%Y-%m-%d %I:%M:%S %p")
|
||||
self.magenta("[+] Crafty: {} - DEBUG:\t{}".format(dt, message))
|
||||
self.magenta(f"[+] Crafty: {dt} - DEBUG:\t{message}")
|
||||
|
||||
def info(self, message):
|
||||
dt = datetime.datetime.now().strftime("%Y-%m-%d %I:%M:%S %p")
|
||||
self.white("[+] Crafty: {} - INFO:\t{}".format(dt, message))
|
||||
self.white(f"[+] Crafty: {dt} - INFO:\t{message}")
|
||||
|
||||
def warning(self, message):
|
||||
dt = datetime.datetime.now().strftime("%Y-%m-%d %I:%M:%S %p")
|
||||
self.cyan("[+] Crafty: {} - WARNING:\t{}".format(dt, message))
|
||||
self.cyan(f"[+] Crafty: {dt} - WARNING:\t{message}")
|
||||
|
||||
def error(self, message):
|
||||
dt = datetime.datetime.now().strftime("%Y-%m-%d %I:%M:%S %p")
|
||||
self.yellow("[+] Crafty: {} - ERROR:\t{}".format(dt, message))
|
||||
self.yellow(f"[+] Crafty: {dt} - ERROR:\t{message}")
|
||||
|
||||
def critical(self, message):
|
||||
dt = datetime.datetime.now().strftime("%Y-%m-%d %I:%M:%S %p")
|
||||
self.red("[+] Crafty: {} - CRITICAL:\t{}".format(dt, message))
|
||||
self.red(f"[+] Crafty: {dt} - CRITICAL:\t{message}")
|
||||
|
||||
def help(self, message):
|
||||
dt = datetime.datetime.now().strftime("%Y-%m-%d %I:%M:%S %p")
|
||||
self.green("[+] Crafty: {} - HELP:\t{}".format(dt, message))
|
||||
self.green(f"[+] Crafty: {dt} - HELP:\t{message}")
|
||||
|
||||
|
||||
console = Console()
|
||||
|
||||
|
@ -14,15 +14,13 @@ import html
|
||||
import zipfile
|
||||
import pathlib
|
||||
import shutil
|
||||
from requests import get
|
||||
from contextlib import suppress
|
||||
import ctypes
|
||||
import telnetlib
|
||||
from app.classes.web.websocket_helper import websocket_helper
|
||||
|
||||
from datetime import datetime
|
||||
from socket import gethostname
|
||||
from contextlib import suppress
|
||||
from requests import get
|
||||
|
||||
from app.classes.web.websocket_helper import websocket_helper
|
||||
from app.classes.shared.console import console
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@ -32,9 +30,9 @@ try:
|
||||
from OpenSSL import crypto
|
||||
from argon2 import PasswordHasher
|
||||
|
||||
except ModuleNotFoundError as e:
|
||||
logger.critical("Import Error: Unable to load {} module".format(e.name), exc_info=True)
|
||||
console.critical("Import Error: Unable to load {} module".format(e.name))
|
||||
except ModuleNotFoundError as err:
|
||||
logger.critical(f"Import Error: Unable to load {err.name} module", exc_info=True)
|
||||
console.critical(f"Import Error: Unable to load {err.name} module")
|
||||
sys.exit(1)
|
||||
|
||||
class Helpers:
|
||||
@ -68,8 +66,8 @@ class Helpers:
|
||||
|
||||
def check_file_perms(self, path):
|
||||
try:
|
||||
fp = open(path, "r").close()
|
||||
logger.info("{} is readable".format(path))
|
||||
open(path, "r", encoding='utf-8').close()
|
||||
logger.info(f"{path} is readable")
|
||||
return True
|
||||
except PermissionError:
|
||||
return False
|
||||
@ -82,7 +80,7 @@ class Helpers:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
logger.error("{} does not exist".format(file))
|
||||
logger.error(f"{file} does not exist")
|
||||
return True
|
||||
|
||||
def get_servers_root_dir(self):
|
||||
@ -93,7 +91,7 @@ class Helpers:
|
||||
try:
|
||||
requests.get('https://google.com', timeout=1)
|
||||
return True
|
||||
except Exception as err:
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
@ -139,7 +137,7 @@ class Helpers:
|
||||
esc = False # whether an escape character was encountered
|
||||
stch = 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 == True: # if set, begin a new argument and increment the command index. Continue the loop.
|
||||
if np: # if set, begin a new argument and increment the command index. Continue the loop.
|
||||
if c == ' ':
|
||||
continue
|
||||
else:
|
||||
@ -154,11 +152,13 @@ class Helpers:
|
||||
else:
|
||||
if c == '\\': # 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: # if we encounter a space and are not dealing with a quote, set the new argument flag and continue to next loop
|
||||
elif c == ' ' and stch 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
|
||||
elif c == stch: # 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): # 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
|
||||
elif stch is None and (c 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
|
||||
else: # else, just store the character in the current arg
|
||||
cmd_out[ci] += c
|
||||
@ -167,20 +167,20 @@ class Helpers:
|
||||
def get_setting(self, key, default_return=False):
|
||||
|
||||
try:
|
||||
with open(self.settings_file, "r") as f:
|
||||
with open(self.settings_file, "r", encoding='utf-8') as f:
|
||||
data = json.load(f)
|
||||
|
||||
if key in data.keys():
|
||||
return data.get(key)
|
||||
|
||||
else:
|
||||
logger.error("Config File Error: setting {} does not exist".format(key))
|
||||
console.error("Config File Error: setting {} does not exist".format(key))
|
||||
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
|
||||
|
||||
except Exception as e:
|
||||
logger.critical("Config File Error: Unable to read {} due to {}".format(self.settings_file, e))
|
||||
console.critical("Config File Error: Unable to read {} due to {}".format(self.settings_file, 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}")
|
||||
|
||||
return default_return
|
||||
|
||||
@ -199,11 +199,11 @@ class Helpers:
|
||||
def get_version(self):
|
||||
version_data = {}
|
||||
try:
|
||||
with open(os.path.join(self.config_dir, 'version.json'), 'r') as f:
|
||||
with open(os.path.join(self.config_dir, 'version.json'), 'r', encoding='utf-8') as f:
|
||||
version_data = json.load(f)
|
||||
|
||||
except Exception as e:
|
||||
console.critical("Unable to get version data!")
|
||||
console.critical(f"Unable to get version data! \n{e}")
|
||||
|
||||
return version_data
|
||||
|
||||
@ -217,7 +217,7 @@ class Helpers:
|
||||
try:
|
||||
data = json.loads(r.content)
|
||||
except Exception as e:
|
||||
logger.error("Failed to load json content with error: {} ".format(e))
|
||||
logger.error(f"Failed to load json content with error: {e}")
|
||||
|
||||
return data
|
||||
|
||||
@ -225,11 +225,13 @@ class Helpers:
|
||||
def get_version_string(self):
|
||||
|
||||
version_data = self.get_version()
|
||||
major = version_data.get('major', '?')
|
||||
minor = version_data.get('minor', '?')
|
||||
sub = version_data.get('sub', '?')
|
||||
meta = version_data.get('meta', '?')
|
||||
|
||||
# set some defaults if we don't get version_data from our helper
|
||||
version = "{}.{}.{}-{}".format(version_data.get('major', '?'),
|
||||
version_data.get('minor', '?'),
|
||||
version_data.get('sub', '?'),
|
||||
version_data.get('meta', '?'))
|
||||
version = f"{major}.{minor}.{sub}-{meta}"
|
||||
return str(version)
|
||||
|
||||
def encode_pass(self, password):
|
||||
@ -240,7 +242,6 @@ class Helpers:
|
||||
self.passhasher.verify(currenthash, password)
|
||||
return True
|
||||
except:
|
||||
pass
|
||||
return False
|
||||
|
||||
def log_colors(self, line):
|
||||
@ -264,6 +265,7 @@ class Helpers:
|
||||
|
||||
# highlight users keywords
|
||||
for keyword in user_keywords:
|
||||
# pylint: disable=consider-using-f-string
|
||||
search_replace = (r'({})'.format(keyword), r'<span class="mc-log-keyword">\1</span>')
|
||||
replacements.append(search_replace)
|
||||
|
||||
@ -274,7 +276,7 @@ class Helpers:
|
||||
|
||||
|
||||
def validate_traversal(self, base_path, filename):
|
||||
logger.debug("Validating traversal (\"{x}\", \"{y}\")".format(x=base_path, y=filename))
|
||||
logger.debug(f"Validating traversal (\"{base_path}\", \"{filename}\")")
|
||||
base = pathlib.Path(base_path).resolve()
|
||||
file = pathlib.Path(filename)
|
||||
fileabs = base.joinpath(file).resolve()
|
||||
@ -287,8 +289,8 @@ class Helpers:
|
||||
|
||||
def tail_file(self, file_name, number_lines=20):
|
||||
if not self.check_file_exists(file_name):
|
||||
logger.warning("Unable to find file to tail: {}".format(file_name))
|
||||
return ["Unable to find file to tail: {}".format(file_name)]
|
||||
logger.warning(f"Unable to find file to tail: {file_name}")
|
||||
return [f"Unable to find file to tail: {file_name}"]
|
||||
|
||||
# length of lines is X char here
|
||||
avg_line_length = 255
|
||||
@ -297,7 +299,7 @@ class Helpers:
|
||||
line_buffer = number_lines * avg_line_length
|
||||
|
||||
# open our file
|
||||
with open(file_name, 'r') as f:
|
||||
with open(file_name, 'r', encoding='utf-8') as f:
|
||||
|
||||
# seek
|
||||
f.seek(0, 2)
|
||||
@ -313,8 +315,7 @@ class Helpers:
|
||||
lines = f.readlines()
|
||||
|
||||
except Exception as e:
|
||||
logger.warning('Unable to read a line in the file:{} - due to error: {}'.format(file_name, e))
|
||||
pass
|
||||
logger.warning(f'Unable to read a line in the file:{file_name} - due to error: {e}')
|
||||
|
||||
# now we are done getting the lines, let's return it
|
||||
return lines
|
||||
@ -323,14 +324,14 @@ class Helpers:
|
||||
def check_writeable(path: str):
|
||||
filename = os.path.join(path, "tempfile.txt")
|
||||
try:
|
||||
fp = open(filename, "w").close()
|
||||
open(filename, "w", encoding='utf-8').close()
|
||||
os.remove(filename)
|
||||
|
||||
logger.info("{} is writable".format(filename))
|
||||
logger.info(f"{filename} is writable")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
logger.critical("Unable to write to {} - Error: {}".format(path, e))
|
||||
logger.critical(f"Unable to write to {path} - Error: {e}")
|
||||
return False
|
||||
|
||||
def checkRoot(self):
|
||||
@ -360,24 +361,17 @@ class Helpers:
|
||||
try:
|
||||
with zipfile.ZipFile(zip_path, 'r') as zip_ref:
|
||||
zip_ref.extractall(tempDir)
|
||||
for i in range(len(zip_ref.filelist)):
|
||||
for i in enumerate(zip_ref.filelist):
|
||||
if len(zip_ref.filelist) > 1 or not zip_ref.filelist[i].filename.endswith('/'):
|
||||
test = zip_ref.filelist[i].filename
|
||||
break
|
||||
path_list = test.split('/')
|
||||
root_path = path_list[0]
|
||||
'''
|
||||
if len(path_list) > 1:
|
||||
for i in range(len(path_list) - 2):
|
||||
root_path = os.path.join(root_path, path_list[i + 1])
|
||||
'''
|
||||
|
||||
full_root_path = tempDir
|
||||
|
||||
for item in os.listdir(full_root_path):
|
||||
try:
|
||||
shutil.move(os.path.join(full_root_path, item), os.path.join(new_dir, item))
|
||||
except Exception as ex:
|
||||
logger.error('ERROR IN ZIP IMPORT: {}'.format(ex))
|
||||
logger.error(f'ERROR IN ZIP IMPORT: {ex}')
|
||||
except Exception as ex:
|
||||
print(ex)
|
||||
else:
|
||||
@ -394,7 +388,7 @@ class Helpers:
|
||||
|
||||
# if not writeable, let's bomb out
|
||||
if not writeable:
|
||||
logger.critical("Unable to write to {} directory!".format(self.root_dir))
|
||||
logger.critical(f"Unable to write to {self.root_dir} directory!")
|
||||
sys.exit(1)
|
||||
|
||||
# ensure the log directory is there
|
||||
@ -402,20 +396,20 @@ class Helpers:
|
||||
with suppress(FileExistsError):
|
||||
os.makedirs(os.path.join(self.root_dir, 'logs'))
|
||||
except Exception as e:
|
||||
console.error("Failed to make logs directory with error: {} ".format(e))
|
||||
console.error(f"Failed to make logs directory with error: {e} ")
|
||||
|
||||
# ensure the log file is there
|
||||
try:
|
||||
open(log_file, 'a').close()
|
||||
open(log_file, 'a', encoding='utf-8').close()
|
||||
except Exception as e:
|
||||
console.critical("Unable to open log file!")
|
||||
console.critical(f"Unable to open log file! {e}")
|
||||
sys.exit(1)
|
||||
|
||||
# del any old session.lock file as this is a new session
|
||||
try:
|
||||
os.remove(session_log_file)
|
||||
except Exception as e:
|
||||
logger.error("Deleting Session.lock failed with error: {} ".format(e))
|
||||
logger.error(f"Deleting Session.lock failed with error: {e}")
|
||||
|
||||
@staticmethod
|
||||
def get_time_as_string():
|
||||
@ -424,10 +418,10 @@ class Helpers:
|
||||
|
||||
@staticmethod
|
||||
def check_file_exists(path: str):
|
||||
logger.debug('Looking for path: {}'.format(path))
|
||||
logger.debug(f'Looking for path: {path}')
|
||||
|
||||
if os.path.exists(path) and os.path.isfile(path):
|
||||
logger.debug('Found path: {}'.format(path))
|
||||
logger.debug(f'Found path: {path}')
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
@ -436,18 +430,20 @@ class Helpers:
|
||||
def human_readable_file_size(num: int, suffix='B'):
|
||||
for unit in ['', 'K', 'M', 'G', 'T', 'P', 'E', 'Z']:
|
||||
if abs(num) < 1024.0:
|
||||
# pylint: disable=consider-using-f-string
|
||||
return "%3.1f%s%s" % (num, unit, suffix)
|
||||
num /= 1024.0
|
||||
# pylint: disable=consider-using-f-string
|
||||
return "%.1f%s%s" % (num, 'Y', suffix)
|
||||
|
||||
@staticmethod
|
||||
def check_path_exists(path: str):
|
||||
if not path:
|
||||
return False
|
||||
logger.debug('Looking for path: {}'.format(path))
|
||||
logger.debug(f'Looking for path: {path}')
|
||||
|
||||
if os.path.exists(path):
|
||||
logger.debug('Found path: {}'.format(path))
|
||||
logger.debug(f'Found path: {path}')
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
@ -459,17 +455,17 @@ class Helpers:
|
||||
|
||||
if os.path.exists(path) and os.path.isfile(path):
|
||||
try:
|
||||
with open(path, 'r') as f:
|
||||
with open(path, 'r', encoding='utf-8') as f:
|
||||
for line in (f.readlines() [-lines:]):
|
||||
contents = contents + line
|
||||
|
||||
return contents
|
||||
|
||||
except Exception as e:
|
||||
logger.error("Unable to read file: {}. \n Error: ".format(path, e))
|
||||
logger.error(f"Unable to read file: {path}. \n Error: {e}")
|
||||
return False
|
||||
else:
|
||||
logger.error("Unable to read file: {}. File not found, or isn't a file.".format(path))
|
||||
logger.error(f"Unable to read file: {path}. File not found, or isn't a file.")
|
||||
return False
|
||||
|
||||
def create_session_file(self, ignore=False):
|
||||
@ -484,11 +480,10 @@ class Helpers:
|
||||
data = json.loads(file_data)
|
||||
pid = data.get('pid')
|
||||
started = data.get('started')
|
||||
console.critical("Another Crafty Controller agent seems to be running...\npid: {} \nstarted on: {}".format(pid, started))
|
||||
console.critical(f"Another Crafty Controller agent seems to be running...\npid: {pid} \nstarted on: {started}")
|
||||
except Exception as e:
|
||||
logger.error("Failed to locate existing session.lock with error: {} ".format(e))
|
||||
console.error("Failed to locate existing session.lock with error: {} ".format(e))
|
||||
|
||||
logger.error(f"Failed to locate existing session.lock with error: {e} ")
|
||||
console.error(f"Failed to locate existing session.lock with error: {e} ")
|
||||
|
||||
sys.exit(1)
|
||||
|
||||
@ -499,7 +494,7 @@ class Helpers:
|
||||
'pid': pid,
|
||||
'started': now.strftime("%d-%m-%Y, %H:%M:%S")
|
||||
}
|
||||
with open(self.session_file, 'w') as f:
|
||||
with open(self.session_file, 'w', encoding='utf-8') as f:
|
||||
json.dump(session_data, f, indent=True)
|
||||
|
||||
# because this is a recursive function, we will return bytes, and set human readable later
|
||||
@ -526,14 +521,14 @@ class Helpers:
|
||||
return sizes
|
||||
|
||||
@staticmethod
|
||||
def base64_encode_string(string: str):
|
||||
s_bytes = str(string).encode('utf-8')
|
||||
def base64_encode_string(fun_str: str):
|
||||
s_bytes = str(fun_str).encode('utf-8')
|
||||
b64_bytes = base64.encodebytes(s_bytes)
|
||||
return b64_bytes.decode('utf-8')
|
||||
|
||||
@staticmethod
|
||||
def base64_decode_string(string: str):
|
||||
s_bytes = str(string).encode('utf-8')
|
||||
def base64_decode_string(fun_str: str):
|
||||
s_bytes = str(fun_str).encode('utf-8')
|
||||
b64_bytes = base64.decodebytes(s_bytes)
|
||||
return b64_bytes.decode("utf-8")
|
||||
|
||||
@ -553,7 +548,7 @@ class Helpers:
|
||||
|
||||
try:
|
||||
os.makedirs(path)
|
||||
logger.debug("Created Directory : {}".format(path))
|
||||
logger.debug(f"Created Directory : {path}")
|
||||
|
||||
# directory already exists - non-blocking error
|
||||
except FileExistsError:
|
||||
@ -570,8 +565,8 @@ class Helpers:
|
||||
cert_file = os.path.join(cert_dir, 'commander.cert.pem')
|
||||
key_file = os.path.join(cert_dir, 'commander.key.pem')
|
||||
|
||||
logger.info("SSL Cert File is set to: {}".format(cert_file))
|
||||
logger.info("SSL Key File is set to: {}".format(key_file))
|
||||
logger.info(f"SSL Cert File is set to: {cert_file}")
|
||||
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):
|
||||
@ -602,11 +597,11 @@ class Helpers:
|
||||
cert.set_pubkey(k)
|
||||
cert.sign(k, 'sha256')
|
||||
|
||||
f = open(cert_file, "w")
|
||||
f = open(cert_file, "w", encoding='utf-8')
|
||||
f.write(crypto.dump_certificate(crypto.FILETYPE_PEM, cert).decode())
|
||||
f.close()
|
||||
|
||||
f = open(key_file, "w")
|
||||
f = open(key_file, "w", encoding='utf-8')
|
||||
f.write(crypto.dump_privatekey(crypto.FILETYPE_PEM, k).decode())
|
||||
f.close()
|
||||
|
||||
@ -645,7 +640,7 @@ class Helpers:
|
||||
data = {}
|
||||
|
||||
if self.check_file_exists(default_file):
|
||||
with open(default_file, 'r') as f:
|
||||
with open(default_file, 'r', encoding='utf-8') as f:
|
||||
data = json.load(f)
|
||||
|
||||
del_json = helper.get_setting('delete_default_json')
|
||||
@ -662,25 +657,26 @@ class Helpers:
|
||||
for raw_filename in file_list:
|
||||
filename = html.escape(raw_filename)
|
||||
rel = os.path.join(folder, raw_filename)
|
||||
dpath = os.path.join(folder, filename)
|
||||
if os.path.isdir(rel):
|
||||
output += \
|
||||
"""<li class="tree-item" data-path="{}">
|
||||
\n<div id="{}" data-path="{}" data-name="{}" class="tree-caret tree-ctx-item tree-folder">
|
||||
<span id="{}span" class="files-tree-title" data-path="{}" data-name="{}" onclick="getDirView(event)">
|
||||
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>
|
||||
{}
|
||||
{filename}
|
||||
</span>
|
||||
</div><li>
|
||||
\n"""\
|
||||
.format(os.path.join(folder, filename), os.path.join(folder, filename), os.path.join(folder, filename), filename, os.path.join(folder, filename), os.path.join(folder, filename), filename, filename)
|
||||
|
||||
else:
|
||||
if filename != "crafty_managed.txt":
|
||||
output += """<li
|
||||
output += f"""<li
|
||||
class="tree-item tree-ctx-item tree-file"
|
||||
data-path="{}"
|
||||
data-name="{}"
|
||||
onclick="clickOnFile(event)"><span style="margin-right: 6px;"><i class="far fa-file"></i></span>{}</li>""".format(os.path.join(folder, filename), filename, filename)
|
||||
data-path="{dpath}"
|
||||
data-name="{filename}"
|
||||
onclick="clickOnFile(event)"><span style="margin-right: 6px;"><i class="far fa-file"></i></span>{filename}</li>"""
|
||||
return output
|
||||
|
||||
@staticmethod
|
||||
@ -688,29 +684,30 @@ class Helpers:
|
||||
file_list = os.listdir(folder)
|
||||
file_list = sorted(file_list, key=str.casefold)
|
||||
output += \
|
||||
"""<ul class="tree-nested d-block" id="{}ul">"""\
|
||||
.format(folder)
|
||||
f"""<ul class="tree-nested d-block" id="{folder}ul">"""\
|
||||
|
||||
for raw_filename in file_list:
|
||||
filename = html.escape(raw_filename)
|
||||
dpath = os.path.join(folder, filename)
|
||||
rel = os.path.join(folder, raw_filename)
|
||||
if os.path.isdir(rel):
|
||||
output += \
|
||||
"""<li class="tree-item" data-path="{}">
|
||||
\n<div id="{}" data-path="{}" data-name="{}" class="tree-caret tree-ctx-item tree-folder">
|
||||
<span id="{}span" class="files-tree-title" data-path="{}" data-name="{}" onclick="getDirView(event)">
|
||||
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>
|
||||
{}
|
||||
{filename}
|
||||
</span>
|
||||
</div><li>"""\
|
||||
.format(os.path.join(folder, filename), os.path.join(folder, filename), os.path.join(folder, filename), filename, os.path.join(folder, filename), os.path.join(folder, filename), filename, filename)
|
||||
|
||||
else:
|
||||
if filename != "crafty_managed.txt":
|
||||
output += """<li
|
||||
output += f"""<li
|
||||
class="tree-item tree-ctx-item tree-file"
|
||||
data-path="{}"
|
||||
data-name="{}"
|
||||
onclick="clickOnFile(event)"><span style="margin-right: 6px;"><i class="far fa-file"></i></span>{}</li>""".format(os.path.join(folder, filename), filename, filename)
|
||||
data-path="{dpath}"
|
||||
data-name="{filename}"
|
||||
onclick="clickOnFile(event)"><span style="margin-right: 6px;"><i class="far fa-file"></i></span>{filename}</li>"""
|
||||
output += '</ul>\n'
|
||||
return output
|
||||
|
||||
@ -719,24 +716,25 @@ class Helpers:
|
||||
file_list = os.listdir(folder)
|
||||
file_list = sorted(file_list, key=str.casefold)
|
||||
output += \
|
||||
"""<ul class="tree-nested d-block" id="{}ul">"""\
|
||||
.format(folder)
|
||||
f"""<ul class="tree-nested d-block" id="{folder}ul">"""\
|
||||
|
||||
for raw_filename in file_list:
|
||||
filename = html.escape(raw_filename)
|
||||
rel = os.path.join(folder, raw_filename)
|
||||
dpath = os.path.join(folder, filename)
|
||||
if os.path.isdir(rel):
|
||||
output += \
|
||||
"""<li class="tree-item" data-path="{}">
|
||||
\n<div id="{}" data-path="{}" data-name="{}" class="tree-caret tree-ctx-item tree-folder">
|
||||
<input type="radio" name="root_path" value="{}">
|
||||
<span id="{}span" class="files-tree-title" data-path="{}" data-name="{}" onclick="getDirView(event)">
|
||||
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="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>
|
||||
{}
|
||||
{filename}
|
||||
</span>
|
||||
</input></div><li>
|
||||
\n"""\
|
||||
.format(os.path.join(folder, filename), os.path.join(folder, filename), os.path.join(folder, filename), filename, os.path.join(folder, filename), os.path.join(folder, filename), os.path.join(folder, filename), filename, filename)
|
||||
|
||||
return output
|
||||
|
||||
@staticmethod
|
||||
@ -744,23 +742,24 @@ class Helpers:
|
||||
file_list = os.listdir(folder)
|
||||
file_list = sorted(file_list, key=str.casefold)
|
||||
output += \
|
||||
"""<ul class="tree-nested d-block" id="{}ul">"""\
|
||||
.format(folder)
|
||||
f"""<ul class="tree-nested d-block" id="{folder}ul">"""\
|
||||
|
||||
for raw_filename in file_list:
|
||||
filename = html.escape(raw_filename)
|
||||
rel = os.path.join(folder, raw_filename)
|
||||
dpath = os.path.join(folder, filename)
|
||||
if os.path.isdir(rel):
|
||||
output += \
|
||||
"""<li class="tree-item" data-path="{}">
|
||||
\n<div id="{}" data-path="{}" data-name="{}" class="tree-caret tree-ctx-item tree-folder">
|
||||
<input type="radio" name="root_path" value="{}">
|
||||
<span id="{}span" class="files-tree-title" data-path="{}" data-name="{}" onclick="getDirView(event)">
|
||||
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="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>
|
||||
{}
|
||||
{filename}
|
||||
</span>
|
||||
</input></div><li>"""\
|
||||
.format(os.path.join(folder, filename), os.path.join(folder, filename), os.path.join(folder, filename), filename, os.path.join(folder, filename), os.path.join(folder, filename), os.path.join(folder, filename), filename, filename)
|
||||
|
||||
return output
|
||||
|
||||
@staticmethod
|
||||
@ -774,7 +773,6 @@ class Helpers:
|
||||
websocket_helper.broadcast_user(user_id, 'send_temp_path',{
|
||||
'path': tempDir
|
||||
})
|
||||
return
|
||||
|
||||
@staticmethod
|
||||
def unzip_backup_archive(backup_path, zip_name):
|
||||
@ -794,7 +792,9 @@ class Helpers:
|
||||
parent_path = os.path.abspath(parent_path)
|
||||
child_path = os.path.abspath(child_path)
|
||||
|
||||
# Compare the common path of the parent and child path with the common path of just the parent path. Using the commonpath method on just the parent path will regularise the path name in the same way as the comparison that deals with both paths, removing any trailing path separator
|
||||
# Compare the common path of the parent and child path with the common path of just the parent path.
|
||||
# Using the commonpath method on just the parent path will regularise the path name in the same way
|
||||
# as the comparison that deals with both paths, removing any trailing path separator
|
||||
return os.path.commonpath([parent_path]) == os.path.commonpath([parent_path, child_path])
|
||||
|
||||
@staticmethod
|
||||
|
@ -1,7 +1,6 @@
|
||||
import sys
|
||||
import subprocess
|
||||
|
||||
|
||||
class install:
|
||||
|
||||
@staticmethod
|
||||
@ -21,5 +20,4 @@ class install:
|
||||
print("Crafty has installed it's dependencies, please restart Crafty")
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
installer = install()
|
@ -2,34 +2,12 @@ import os
|
||||
import pathlib
|
||||
import time
|
||||
import logging
|
||||
import sys
|
||||
from typing import Union
|
||||
|
||||
from app.classes.models.server_permissions import Enum_Permissions_Server
|
||||
from app.classes.models.users import helper_users
|
||||
from peewee import DoesNotExist
|
||||
import yaml
|
||||
import asyncio
|
||||
import shutil
|
||||
import tempfile
|
||||
import zipfile
|
||||
from distutils import dir_util
|
||||
from app.classes.models.management import helpers_management
|
||||
from app.classes.web.websocket_helper import websocket_helper
|
||||
from typing import Union
|
||||
from peewee import DoesNotExist
|
||||
|
||||
from app.classes.shared.helpers import helper
|
||||
from app.classes.shared.console import console
|
||||
|
||||
# Importing Models
|
||||
from app.classes.models.servers import servers_helper
|
||||
from app.classes.shared.console import console
|
||||
from app.classes.shared.helpers import helper
|
||||
from app.classes.shared.server import Server
|
||||
from app.classes.minecraft.server_props import ServerProps
|
||||
from app.classes.minecraft.serverjars import server_jar_obj
|
||||
from app.classes.minecraft.stats import Stats
|
||||
|
||||
# Importing Controllers
|
||||
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
|
||||
@ -37,6 +15,21 @@ 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
|
||||
from app.classes.shared.server import Server
|
||||
|
||||
from app.classes.minecraft.server_props import ServerProps
|
||||
from app.classes.minecraft.serverjars import server_jar_obj
|
||||
from app.classes.minecraft.stats import Stats
|
||||
|
||||
from app.classes.web.websocket_helper import websocket_helper
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class Controller:
|
||||
@ -53,7 +46,7 @@ class Controller:
|
||||
|
||||
def check_server_loaded(self, server_id_to_check: int):
|
||||
|
||||
logger.info("Checking to see if we already registered {}".format(server_id_to_check))
|
||||
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')
|
||||
@ -61,7 +54,7 @@ class Controller:
|
||||
return False
|
||||
|
||||
if known_server == server_id_to_check:
|
||||
logger.info('skipping initialization of server {} because it is already loaded'.format(server_id_to_check))
|
||||
logger.info(f'skipping initialization of server {server_id_to_check} because it is already loaded')
|
||||
return True
|
||||
|
||||
return False
|
||||
@ -79,19 +72,17 @@ class Controller:
|
||||
|
||||
# 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'])):
|
||||
logger.warning("Unable to find server {} at path {}. Skipping this server".format(s['server_name'],
|
||||
s['path']))
|
||||
logger.warning(f"Unable to find server {s['server_name']} at path {s['path']}. Skipping this server")
|
||||
|
||||
console.warning("Unable to find server {} at path {}. Skipping this server".format(s['server_name'],
|
||||
s['path']))
|
||||
console.warning(f"Unable to find server {s['server_name']} at path {s['path']}. Skipping this server")
|
||||
continue
|
||||
|
||||
settings_file = os.path.join(helper.get_os_understandable_path(s['path']), 'server.properties')
|
||||
|
||||
# if the properties file isn't there, let's warn
|
||||
if not helper.check_file_exists(settings_file):
|
||||
logger.error("Unable to find {}. Skipping this server.".format(settings_file))
|
||||
console.error("Unable to find {}. Skipping this server.".format(settings_file))
|
||||
logger.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)
|
||||
@ -114,12 +105,10 @@ class Controller:
|
||||
|
||||
self.refresh_server_settings(s['server_id'])
|
||||
|
||||
console.info("Loaded Server: ID {} | Name: {} | Autostart: {} | Delay: {} ".format(
|
||||
s['server_id'],
|
||||
s['server_name'],
|
||||
s['auto_start'],
|
||||
s['auto_start_delay']
|
||||
))
|
||||
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']} ")
|
||||
|
||||
def refresh_server_settings(self, server_id: int):
|
||||
server_obj = self.get_server_obj(server_id)
|
||||
@ -155,10 +144,10 @@ class Controller:
|
||||
user_servers = self.servers.get_authorized_servers(int(exec_user['user_id']))
|
||||
auth_servers = []
|
||||
for server in user_servers:
|
||||
if Enum_Permissions_Server.Logs in self.server_perms.get_user_permissions_list(exec_user['user_id'], server["server_id"]):
|
||||
if Enum_Permissions_Server.Logs in self.server_perms.get_user_id_permissions_list(exec_user['user_id'], server["server_id"]):
|
||||
auth_servers.append(server)
|
||||
else:
|
||||
logger.info("Logs permission not available for server {}. Skipping.".format(server["server_name"]))
|
||||
logger.info(f"Logs permission not available for server {server['server_name']}. Skipping.")
|
||||
#we'll iterate through our list of log paths from auth servers.
|
||||
for server in auth_servers:
|
||||
final_path = os.path.join(server_path, str(server['server_name']))
|
||||
@ -166,7 +155,7 @@ class Controller:
|
||||
try:
|
||||
shutil.copy(server['log_path'], final_path)
|
||||
except Exception as e:
|
||||
logger.warning("Failed to copy file with error: {}".format(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')
|
||||
shutil.copytree(os.path.join(self.project_root, 'logs'), full_log_name)
|
||||
@ -187,7 +176,7 @@ class Controller:
|
||||
if int(s['server_id']) == int(server_id):
|
||||
return s['server_settings']
|
||||
|
||||
logger.warning("Unable to find server object for server id {}".format(server_id))
|
||||
logger.warning(f"Unable to find server object for server id {server_id}")
|
||||
return False
|
||||
|
||||
def get_server_obj(self, server_id: Union[str, int]) -> Union[bool, Server]:
|
||||
@ -195,7 +184,7 @@ class Controller:
|
||||
if str(s['server_id']) == str(server_id):
|
||||
return s['server_obj']
|
||||
|
||||
logger.warning("Unable to find server object for server id {}".format(server_id))
|
||||
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):
|
||||
@ -203,7 +192,7 @@ class Controller:
|
||||
if str(s['server_id']) == str(server_id):
|
||||
return s['server_data_obj']
|
||||
|
||||
logger.warning("Unable to find server object for server id {}".format(server_id))
|
||||
logger.warning(f"Unable to find server object for server id {server_id}")
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
@ -231,15 +220,15 @@ class Controller:
|
||||
|
||||
def stop_all_servers(self):
|
||||
servers = self.list_running_servers()
|
||||
logger.info("Found {} running server(s)".format(len(servers)))
|
||||
console.info("Found {} running server(s)".format(len(servers)))
|
||||
logger.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")
|
||||
|
||||
for s in servers:
|
||||
logger.info("Stopping Server ID {} - {}".format(s['id'], s['name']))
|
||||
console.info("Stopping Server ID {} - {}".format(s['id'], s['name']))
|
||||
logger.info(f"Stopping Server ID {s['id']} - {s['name']}")
|
||||
console.info(f"Stopping Server ID {s['id']} - {s['name']}")
|
||||
|
||||
self.stop_server(s['id'])
|
||||
|
||||
@ -264,7 +253,7 @@ class Controller:
|
||||
server_dir.replace(' ', '^ ')
|
||||
backup_path.replace(' ', '^ ')
|
||||
|
||||
server_file = "{server}-{version}.jar".format(server=server, version=version)
|
||||
server_file = f"{server}-{version}.jar"
|
||||
full_jar_path = os.path.join(server_dir, server_file)
|
||||
|
||||
# make the dir - perhaps a UUID?
|
||||
@ -273,32 +262,29 @@ class Controller:
|
||||
|
||||
try:
|
||||
# do a eula.txt
|
||||
with open(os.path.join(server_dir, "eula.txt"), 'w') as f:
|
||||
with open(os.path.join(server_dir, "eula.txt"), 'w', encoding='utf-8') as f:
|
||||
f.write("eula=false")
|
||||
f.close()
|
||||
|
||||
# setup server.properties with the port
|
||||
with open(os.path.join(server_dir, "server.properties"), "w") as f:
|
||||
f.write("server-port={}".format(port))
|
||||
with open(os.path.join(server_dir, "server.properties"), "w", encoding='utf-8') as f:
|
||||
f.write(f"server-port={port}")
|
||||
f.close()
|
||||
|
||||
except Exception as e:
|
||||
logger.error("Unable to create required server files due to :{}".format(e))
|
||||
logger.error(f"Unable to create required server files due to :{e}")
|
||||
return False
|
||||
|
||||
#must remain non-fstring due to string addtion
|
||||
if helper.is_os_windows():
|
||||
server_command = 'java -Xms{}M -Xmx{}M -jar "{}" nogui'.format(helper.float_to_string(min_mem),
|
||||
helper.float_to_string(max_mem),
|
||||
full_jar_path)
|
||||
server_command = f'java -Xms{helper.float_to_string(min_mem)}M -Xmx{helper.float_to_string(max_mem)}M -jar "{full_jar_path}" nogui'
|
||||
else:
|
||||
server_command = 'java -Xms{}M -Xmx{}M -jar {} nogui'.format(helper.float_to_string(min_mem),
|
||||
helper.float_to_string(max_mem),
|
||||
full_jar_path)
|
||||
server_log_file = "{}/logs/latest.log".format(server_dir)
|
||||
server_command = f'java -Xms{helper.float_to_string(min_mem)}M -Xmx{helper.float_to_string(max_mem)}M -jar {full_jar_path} nogui'
|
||||
server_log_file = f"{server_dir}/logs/latest.log"
|
||||
server_stop = "stop"
|
||||
|
||||
# download the jar
|
||||
server_jar_obj.download_jar(server, version, full_jar_path, name)
|
||||
server_jar_obj.download_jar(server, version, full_jar_path)
|
||||
|
||||
new_id = self.register_server(name, server_id, server_dir, backup_path, server_command, server_file, server_log_file, server_stop, port)
|
||||
return new_id
|
||||
@ -340,22 +326,19 @@ class Controller:
|
||||
if str(item) == 'server.properties':
|
||||
has_properties = True
|
||||
if not has_properties:
|
||||
logger.info("No server.properties found on zip file import. Creating one with port selection of {}".format(str(port)))
|
||||
with open(os.path.join(new_server_dir, "server.properties"), "w") as f:
|
||||
f.write("server-port={}".format(port))
|
||||
logger.info(f"No server.properties found on zip file import. Creating one with port selection of {str(port)}")
|
||||
with open(os.path.join(new_server_dir, "server.properties"), "w", encoding='utf-8') as f:
|
||||
f.write(f"server-port={port}")
|
||||
f.close()
|
||||
|
||||
full_jar_path = os.path.join(new_server_dir, server_jar)
|
||||
|
||||
#due to adding strings this must not be an fstring
|
||||
if helper.is_os_windows():
|
||||
server_command = 'java -Xms{}M -Xmx{}M -jar {} nogui'.format(helper.float_to_string(min_mem),
|
||||
helper.float_to_string(max_mem),
|
||||
'"'+full_jar_path+'"')
|
||||
server_command = f'java -Xms{helper.float_to_string(min_mem)}M -Xmx{helper.float_to_string(max_mem)}M -jar "{full_jar_path}" nogui'
|
||||
else:
|
||||
server_command = 'java -Xms{}M -Xmx{}M -jar {} nogui'.format(helper.float_to_string(min_mem),
|
||||
helper.float_to_string(max_mem),
|
||||
full_jar_path)
|
||||
server_log_file = "{}/logs/latest.log".format(new_server_dir)
|
||||
server_command = f'java -Xms{helper.float_to_string(min_mem)}M -Xmx{helper.float_to_string(max_mem)}M -jar {full_jar_path} nogui'
|
||||
server_log_file = f"{new_server_dir}/logs/latest.log"
|
||||
server_stop = "stop"
|
||||
|
||||
new_id = self.register_server(server_name, server_id, new_server_dir, backup_path, server_command, server_jar,
|
||||
@ -383,25 +366,22 @@ class Controller:
|
||||
try:
|
||||
shutil.move(os.path.join(tempDir, item), os.path.join(new_server_dir, item))
|
||||
except Exception as ex:
|
||||
logger.error('ERROR IN ZIP IMPORT: {}'.format(ex))
|
||||
logger.error(f'ERROR IN ZIP IMPORT: {ex}')
|
||||
if not has_properties:
|
||||
logger.info("No server.properties found on zip file import. Creating one with port selection of {}".format(str(port)))
|
||||
with open(os.path.join(new_server_dir, "server.properties"), "w") as f:
|
||||
f.write("server-port={}".format(port))
|
||||
logger.info(f"No server.properties found on zip file import. Creating one with port selection of {str(port)}")
|
||||
with open(os.path.join(new_server_dir, "server.properties"), "w", encoding='utf-8') as f:
|
||||
f.write(f"server-port={port}")
|
||||
f.close()
|
||||
|
||||
full_jar_path = os.path.join(new_server_dir, server_jar)
|
||||
|
||||
#due to strings being added we need to leave this as not an fstring
|
||||
if helper.is_os_windows():
|
||||
server_command = 'java -Xms{}M -Xmx{}M -jar {} nogui'.format(helper.float_to_string(min_mem),
|
||||
helper.float_to_string(max_mem),
|
||||
'"'+full_jar_path+'"')
|
||||
server_command = f'java -Xms{helper.float_to_string(min_mem)}M -Xmx{helper.float_to_string(max_mem)}M -jar "{full_jar_path}" nogui'
|
||||
else:
|
||||
server_command = 'java -Xms{}M -Xmx{}M -jar {} nogui'.format(helper.float_to_string(min_mem),
|
||||
helper.float_to_string(max_mem),
|
||||
full_jar_path)
|
||||
server_command = f'java -Xms{helper.float_to_string(min_mem)}M -Xmx{helper.float_to_string(max_mem)}M -jar {full_jar_path} nogui'
|
||||
logger.debug('command: ' + server_command)
|
||||
server_log_file = "{}/logs/latest.log".format(new_server_dir)
|
||||
server_log_file = f"{new_server_dir}/logs/latest.log"
|
||||
server_stop = "stop"
|
||||
|
||||
new_id = self.register_server(server_name, server_id, new_server_dir, backup_path, server_command, server_jar,
|
||||
@ -424,20 +404,30 @@ class Controller:
|
||||
os.rmdir(new_bu_path)
|
||||
backup_path.rename(new_bu_path)
|
||||
|
||||
def register_server(self, name: str, server_uuid: str, server_dir: str, backup_path: str, server_command: str, server_file: str, server_log_file: str, server_stop: str, server_port: int):
|
||||
def register_server(self, name: str,
|
||||
server_uuid: str,
|
||||
server_dir: str,
|
||||
backup_path: str,
|
||||
server_command: str,
|
||||
server_file: str,
|
||||
server_log_file: str,
|
||||
server_stop: str,
|
||||
server_port: int):
|
||||
# put data in the db
|
||||
|
||||
new_id = self.servers.create_server(name, server_uuid, server_dir, backup_path, server_command, server_file, server_log_file, server_stop, server_port)
|
||||
new_id = self.servers.create_server(
|
||||
name, server_uuid, server_dir, backup_path, server_command, server_file, server_log_file, server_stop, server_port)
|
||||
|
||||
if not helper.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') as f:
|
||||
with open(os.path.join(server_dir, "crafty_managed.txt"), 'w', encoding='utf-8') as f:
|
||||
f.write(
|
||||
"The server is managed by Crafty Controller.\n Leave this directory/files alone please")
|
||||
f.close()
|
||||
|
||||
except Exception as e:
|
||||
logger.error("Unable to create required server files due to :{}".format(e))
|
||||
logger.error(f"Unable to create required server files due to :{e}")
|
||||
return False
|
||||
|
||||
# let's re-init all servers
|
||||
@ -453,10 +443,9 @@ class Controller:
|
||||
if str(s['server_id']) == str(server_id):
|
||||
server_data = self.get_server_data(server_id)
|
||||
server_name = server_data['server_name']
|
||||
backup_dir = self.servers.get_server_data_by_id(server_id)['backup_path']
|
||||
|
||||
logger.info("Deleting Server: ID {} | Name: {} ".format(server_id, server_name))
|
||||
console.info("Deleting Server: ID {} | Name: {} ".format(server_id, server_name))
|
||||
logger.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']
|
||||
running = srv_obj.check_running()
|
||||
@ -467,7 +456,7 @@ class Controller:
|
||||
try:
|
||||
shutil.rmtree(helper.get_os_understandable_path(self.servers.get_server_data_by_id(server_id)['path']))
|
||||
except Exception as e:
|
||||
logger.error("Unable to delete server files for server with ID: {} with error logged: {}".format(server_id, e))
|
||||
logger.error(f"Unable to delete server files for server with ID: {server_id} with error logged: {e}")
|
||||
if helper.check_path_exists(self.servers.get_server_data_by_id(server_id)['backup_path']):
|
||||
shutil.rmtree(helper.get_os_understandable_path(self.servers.get_server_data_by_id(server_id)['backup_path']))
|
||||
|
||||
@ -484,4 +473,3 @@ class Controller:
|
||||
self.servers_list.pop(counter)
|
||||
|
||||
counter += 1
|
||||
return
|
||||
|
@ -1,32 +1,27 @@
|
||||
import os
|
||||
import sys
|
||||
import logging
|
||||
import datetime
|
||||
|
||||
from app.classes.shared.helpers import helper
|
||||
from app.classes.shared.console import console
|
||||
from app.classes.models.users import Users, users_helper
|
||||
from app.classes.minecraft.server_props import ServerProps
|
||||
from app.classes.web.websocket_helper import websocket_helper
|
||||
|
||||
from app.classes.models.users import Users, users_helper
|
||||
|
||||
# To disable warning about unused import ; Users is imported from here in other places
|
||||
#pylint: disable=self-assigning-variable
|
||||
Users = Users
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
peewee_logger = logging.getLogger('peewee')
|
||||
peewee_logger.setLevel(logging.INFO)
|
||||
|
||||
try:
|
||||
from peewee import *
|
||||
# pylint: disable=unused-import
|
||||
from peewee import SqliteDatabase, fn
|
||||
from playhouse.shortcuts import model_to_dict
|
||||
from enum import Enum
|
||||
import yaml
|
||||
|
||||
except ModuleNotFoundError as e:
|
||||
logger.critical("Import Error: Unable to load {} module".format(e.name), exc_info=True)
|
||||
console.critical("Import Error: Unable to load {} module".format(e.name))
|
||||
except ModuleNotFoundError as err:
|
||||
logger.critical(f"Import Error: Unable to load {err.name} module", exc_info=True)
|
||||
console.critical(f"Import Error: Unable to load {err.name} module")
|
||||
sys.exit(1)
|
||||
|
||||
database = SqliteDatabase(helper.db_path, pragmas={
|
||||
@ -43,24 +38,17 @@ class db_builder:
|
||||
|
||||
username = default_data.get("username", 'admin')
|
||||
password = default_data.get("password", 'crafty')
|
||||
#
|
||||
#Users.insert({
|
||||
# Users.username: username.lower(),
|
||||
# Users.password: helper.encode_pass(password),
|
||||
# Users.enabled: True,
|
||||
# Users.superuser: True
|
||||
#}).execute()
|
||||
user_id = users_helper.add_user(username=username, password=password, email="default@example.com", superuser=True)
|
||||
#users_helper.update_user(user_id, user_crafty_data={"permissions_mask":"111", "server_quantity":[-1,-1,-1]} )
|
||||
|
||||
users_helper.add_user(username=username, password=password, email="default@example.com", superuser=True)
|
||||
|
||||
@staticmethod
|
||||
def is_fresh_install():
|
||||
try:
|
||||
user = users_helper.get_by_id(1)
|
||||
if user:
|
||||
return False
|
||||
except:
|
||||
return True
|
||||
pass
|
||||
|
||||
class db_shortcuts:
|
||||
|
||||
@ -76,8 +64,7 @@ class db_shortcuts:
|
||||
for s in query:
|
||||
rows.append(model_to_dict(s))
|
||||
except Exception as e:
|
||||
logger.warning("Database Error: {}".format(e))
|
||||
pass
|
||||
logger.warning(f"Database Error: {e}")
|
||||
|
||||
return rows
|
||||
|
||||
|
@ -5,7 +5,7 @@ import sys
|
||||
import os
|
||||
import re
|
||||
from functools import wraps
|
||||
|
||||
# pylint: disable=no-name-in-module
|
||||
from functools import cached_property
|
||||
|
||||
from app.classes.shared.helpers import helper
|
||||
@ -16,16 +16,14 @@ logger = logging.getLogger(__name__)
|
||||
try:
|
||||
import peewee
|
||||
from playhouse.migrate import (
|
||||
SchemaMigrator as ScM,
|
||||
SqliteMigrator,
|
||||
Operation, SQL, operation, SqliteDatabase,
|
||||
make_index_name, Context
|
||||
Operation, SQL, SqliteDatabase,
|
||||
make_index_name
|
||||
)
|
||||
|
||||
except ModuleNotFoundError as e:
|
||||
logger.critical("Import Error: Unable to load {} module".format(
|
||||
e.name), exc_info=True)
|
||||
console.critical("Import Error: Unable to load {} module".format(e.name))
|
||||
logger.critical(f"Import Error: Unable to load {e.name} module", exc_info=True)
|
||||
console.critical(f"Import Error: Unable to load {e.name} module")
|
||||
sys.exit(1)
|
||||
|
||||
MIGRATE_TABLE = 'migratehistory'
|
||||
@ -78,7 +76,7 @@ def get_model(method):
|
||||
|
||||
|
||||
# noinspection PyProtectedMember
|
||||
class Migrator(object):
|
||||
class Migrator():
|
||||
def __init__(self, database: t.Union[peewee.Database, peewee.Proxy]):
|
||||
"""
|
||||
Initializes the migrator
|
||||
@ -105,7 +103,7 @@ class Migrator(object):
|
||||
"""
|
||||
Cleans the operations.
|
||||
"""
|
||||
self.operations = list()
|
||||
self.operations = []
|
||||
|
||||
def sql(self, sql: str, *params):
|
||||
"""
|
||||
@ -279,7 +277,7 @@ class Migrator(object):
|
||||
|
||||
|
||||
# noinspection PyProtectedMember
|
||||
class MigrationManager(object):
|
||||
class MigrationManager():
|
||||
filemask = re.compile(r"[\d]+_[^\.]+\.py$")
|
||||
|
||||
def __init__(self, database: t.Union[peewee.Database, peewee.Proxy]):
|
||||
@ -287,7 +285,7 @@ class MigrationManager(object):
|
||||
Initializes the migration manager.
|
||||
"""
|
||||
if not isinstance(database, (peewee.Database, peewee.Proxy)):
|
||||
raise RuntimeError('Invalid database: {}'.format(database))
|
||||
raise RuntimeError(f'Invalid database: {database}')
|
||||
self.database = database
|
||||
|
||||
@cached_property
|
||||
@ -295,6 +293,7 @@ class MigrationManager(object):
|
||||
"""
|
||||
Initialize and cache the MigrationHistory model.
|
||||
"""
|
||||
#pylint: disable=no-member
|
||||
MigrateHistory._meta.database = self.database
|
||||
MigrateHistory._meta.table_name = 'migratehistory'
|
||||
MigrateHistory._meta.schema = None
|
||||
@ -306,6 +305,7 @@ class MigrationManager(object):
|
||||
"""
|
||||
Scans migrations in the database.
|
||||
"""
|
||||
# pylint: disable=no-member
|
||||
return [mm.name for mm in self.model.select().order_by(self.model.id)]
|
||||
|
||||
@property
|
||||
@ -314,8 +314,7 @@ class MigrationManager(object):
|
||||
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))
|
||||
logger.warning(f'Migration directory: {helper.migration_dir} does not exist.')
|
||||
os.makedirs(helper.migration_dir)
|
||||
return sorted(f[:-3] for f in os.listdir(helper.migration_dir) if self.filemask.match(f))
|
||||
|
||||
@ -344,7 +343,7 @@ class MigrationManager(object):
|
||||
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:
|
||||
with open(path, 'w', encoding='utf-8') as f:
|
||||
f.write(MIGRATE_TEMPLATE.format(
|
||||
migrate=migrate, rollback=rollback, name=filename))
|
||||
|
||||
@ -358,13 +357,14 @@ class MigrationManager(object):
|
||||
if auto:
|
||||
raise NotImplementedError
|
||||
|
||||
logger.info('Creating migration "{}"'.format(name))
|
||||
logger.info(f'Creating migration "{name}"')
|
||||
name = self.compile(name, migrate, rollback)
|
||||
logger.info('Migration has been created as "{}"'.format(name))
|
||||
logger.info(f'Migration has been created as "{name}"')
|
||||
return name
|
||||
|
||||
def clear(self):
|
||||
"""Clear migrations."""
|
||||
# pylint: disable=no-member
|
||||
self.model.delete().execute()
|
||||
|
||||
def up(self, name: t.Optional[str] = None):
|
||||
@ -381,7 +381,6 @@ class MigrationManager(object):
|
||||
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:
|
||||
@ -393,14 +392,15 @@ class MigrationManager(object):
|
||||
"""
|
||||
Reads a migration from a file.
|
||||
"""
|
||||
call_params = dict()
|
||||
call_params = {}
|
||||
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:
|
||||
with open(os.path.join(helper.migration_dir, name + '.py'), **call_params, encoding='utf-8') as f:
|
||||
code = f.read()
|
||||
scope = {}
|
||||
code = compile(code, '<string>', 'exec', dont_inherit=True)
|
||||
# pylint: disable=exec-used
|
||||
exec(code, scope, None)
|
||||
return scope.get('migrate', lambda m, d: None), scope.get('rollback', lambda m, d: None)
|
||||
|
||||
@ -417,24 +417,26 @@ class MigrationManager(object):
|
||||
return name
|
||||
with self.database.transaction():
|
||||
if rollback:
|
||||
logger.info('Rolling back "{}"'.format(name))
|
||||
logger.info(f'Rolling back "{name}"')
|
||||
rollback_fn(migrator, self.database)
|
||||
migrator.run()
|
||||
# pylint: disable=no-member
|
||||
self.model.delete().where(self.model.name == name).execute()
|
||||
else:
|
||||
logger.info('Migrate "{}"'.format(name))
|
||||
logger.info(f'Migrate "{name}"')
|
||||
migrate_fn(migrator, self.database)
|
||||
migrator.run()
|
||||
if name not in self.done:
|
||||
# pylint: disable=no-member
|
||||
self.model.create(name=name)
|
||||
|
||||
logger.info('Done "{}"'.format(name))
|
||||
logger.info(f'Done "{name}"')
|
||||
return name
|
||||
|
||||
except Exception:
|
||||
self.database.rollback()
|
||||
operation_name = 'Rollback' if rollback else 'Migration'
|
||||
logger.exception('{} failed: {}'.format(operation_name, name))
|
||||
logger.exception(f'{operation_name} failed: {name}')
|
||||
raise
|
||||
|
||||
def down(self):
|
||||
@ -448,4 +450,4 @@ class MigrationManager(object):
|
||||
|
||||
migrator = self.migrator
|
||||
self.up_one(name, migrator, False, True)
|
||||
logger.warning('Rolled back migration: {}'.format(name))
|
||||
logger.warning(f'Rolled back migration: {name}')
|
||||
|
@ -1,6 +1,5 @@
|
||||
from enum import Enum
|
||||
|
||||
|
||||
class PermissionHelper:
|
||||
@staticmethod
|
||||
def both_have_perm(a: str, b: str, permission_tested: Enum):
|
||||
|
@ -1,42 +1,36 @@
|
||||
import os
|
||||
import sys
|
||||
import re
|
||||
import json
|
||||
import time
|
||||
import datetime
|
||||
import threading
|
||||
import logging.config
|
||||
import zipfile
|
||||
from threading import Thread
|
||||
import shutil
|
||||
import subprocess
|
||||
import zlib
|
||||
import html
|
||||
import apscheduler
|
||||
from apscheduler.schedulers.background import BackgroundScheduler
|
||||
#TZLocal is set as a hidden import on win pipeline
|
||||
from tzlocal import get_localzone
|
||||
|
||||
|
||||
from app.classes.shared.helpers import helper
|
||||
from app.classes.shared.console import console
|
||||
from app.classes.models.servers import Servers, helper_servers, servers_helper
|
||||
from app.classes.models.servers import servers_helper
|
||||
from app.classes.models.management import management_helper
|
||||
from app.classes.web.websocket_helper import websocket_helper
|
||||
from app.classes.shared.translation import translation
|
||||
from app.classes.models.users import users_helper
|
||||
from app.classes.models.server_permissions import server_permissions
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
from app.classes.shared.helpers import helper
|
||||
from app.classes.shared.console import console
|
||||
from app.classes.shared.translation import translation
|
||||
|
||||
from app.classes.web.websocket_helper import websocket_helper
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
try:
|
||||
import psutil
|
||||
#import pexpect
|
||||
|
||||
except ModuleNotFoundError as e:
|
||||
logger.critical("Import Error: Unable to load {} module".format(e.name), exc_info=True)
|
||||
console.critical("Import Error: Unable to load {} module".format(e.name))
|
||||
logger.critical(f"Import Error: Unable to load {e.name} module", exc_info=True)
|
||||
console.critical(f"Import Error: Unable to load {e.name} module")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
@ -118,7 +112,6 @@ class Server:
|
||||
self.name = None
|
||||
self.is_crashed = False
|
||||
self.restart_count = 0
|
||||
self.crash_watcher_schedule = None
|
||||
self.stats = stats
|
||||
tz = get_localzone()
|
||||
self.server_scheduler = BackgroundScheduler(timezone=str(tz))
|
||||
@ -130,13 +123,13 @@ class Server:
|
||||
self.settings = server_data
|
||||
|
||||
def do_server_setup(self, server_data_obj):
|
||||
logger.info('Creating Server object: {} | Server Name: {} | Auto Start: {}'.format(
|
||||
server_data_obj['server_id'],
|
||||
server_data_obj['server_name'],
|
||||
server_data_obj['auto_start']
|
||||
))
|
||||
self.server_id = server_data_obj['server_id']
|
||||
self.name = server_data_obj['server_name']
|
||||
serverId = server_data_obj['server_id']
|
||||
serverName = server_data_obj['server_name']
|
||||
autoStart = server_data_obj['auto_start']
|
||||
|
||||
logger.info(f'Creating Server object: {serverId} | Server Name: {serverName} | Auto Start: {autoStart}')
|
||||
self.server_id = serverId
|
||||
self.name = serverName
|
||||
self.settings = server_data_obj
|
||||
|
||||
# build our server run command
|
||||
@ -144,15 +137,15 @@ class Server:
|
||||
if server_data_obj['auto_start']:
|
||||
delay = int(self.settings['auto_start_delay'])
|
||||
|
||||
logger.info("Scheduling server {} to start in {} seconds".format(self.name, delay))
|
||||
console.info("Scheduling server {} to start in {} seconds".format(self.name, delay))
|
||||
logger.info(f"Scheduling server {self.name} to start in {delay} seconds")
|
||||
console.info(f"Scheduling server {self.name} to start in {delay} seconds")
|
||||
|
||||
self.server_scheduler.add_job(self.run_scheduled_server, 'interval', seconds=delay, id=str(self.server_id))
|
||||
self.server_scheduler.start()
|
||||
|
||||
def run_scheduled_server(self):
|
||||
console.info("Starting server ID: {} - {}".format(self.server_id, self.name))
|
||||
logger.info("Starting server {}".format(self.server_id, self.name))
|
||||
console.info(f"Starting server ID: {self.server_id} - {self.name}")
|
||||
logger.info(f"Starting server ID: {self.server_id} - {self.name}")
|
||||
#Sets waiting start to false since we're attempting to start the server.
|
||||
servers_helper.set_waiting_start(self.server_id, False)
|
||||
self.run_threaded_server(None)
|
||||
@ -162,7 +155,7 @@ class Server:
|
||||
|
||||
def run_threaded_server(self, user_id):
|
||||
# start the server
|
||||
self.server_thread = threading.Thread(target=self.start_server, daemon=True, args=(user_id,), name='{}_server_thread'.format(self.server_id))
|
||||
self.server_thread = threading.Thread(target=self.start_server, daemon=True, args=(user_id,), name=f'{self.server_id}_server_thread')
|
||||
self.server_thread.start()
|
||||
|
||||
def setup_server_run_command(self):
|
||||
@ -174,16 +167,16 @@ class Server:
|
||||
# let's do some quick checking to make sure things actually exists
|
||||
full_path = os.path.join(self.server_path, server_exec_path)
|
||||
if not helper.check_file_exists(full_path):
|
||||
logger.critical("Server executable path: {} does not seem to exist".format(full_path))
|
||||
console.critical("Server executable path: {} does not seem to exist".format(full_path))
|
||||
logger.critical(f"Server executable path: {full_path} does not seem to exist")
|
||||
console.critical(f"Server executable path: {full_path} does not seem to exist")
|
||||
|
||||
if not helper.check_path_exists(self.server_path):
|
||||
logger.critical("Server path: {} does not seem to exits".format(self.server_path))
|
||||
console.critical("Server path: {} does not seem to exits".format(self.server_path))
|
||||
logger.critical(f"Server path: {self.server_path} does not seem to exits")
|
||||
console.critical(f"Server path: {self.server_path} does not seem to exits")
|
||||
|
||||
if not helper.check_writeable(self.server_path):
|
||||
logger.critical("Unable to write/access {}".format(self.server_path))
|
||||
console.warning("Unable to write/access {}".format(self.server_path))
|
||||
logger.critical(f"Unable to write/access {self.server_path}")
|
||||
console.warning(f"Unable to write/access {self.server_path}")
|
||||
|
||||
def start_server(self, user_id):
|
||||
if not user_id:
|
||||
@ -191,7 +184,7 @@ class Server:
|
||||
else:
|
||||
user_lang = users_helper.get_user_lang_by_id(user_id)
|
||||
|
||||
logger.info("Start command detected. Reloading settings from DB for server {}".format(self.name))
|
||||
logger.info(f"Start command detected. Reloading settings from DB for server {self.name}")
|
||||
self.setup_server_run_command()
|
||||
# fail safe in case we try to start something already running
|
||||
if self.check_running():
|
||||
@ -202,13 +195,13 @@ class Server:
|
||||
logger.error("Server is updating. Terminating startup.")
|
||||
return False
|
||||
|
||||
logger.info("Launching Server {} with command {}".format(self.name, self.server_command))
|
||||
console.info("Launching Server {} with command {}".format(self.name, self.server_command))
|
||||
logger.info(f"Launching Server {self.name} with command {self.server_command}")
|
||||
console.info(f"Launching Server {self.name} with command {self.server_command}")
|
||||
|
||||
#Checks for eula. Creates one if none detected.
|
||||
#If EULA is detected and not set to one of these true vaiants we offer to set it true.
|
||||
if helper.check_file_exists(os.path.join(self.settings['path'], 'eula.txt')):
|
||||
f = open(os.path.join(self.settings['path'], 'eula.txt'), 'r')
|
||||
f = open(os.path.join(self.settings['path'], 'eula.txt'), 'r', encoding='utf-8')
|
||||
line = f.readline().lower()
|
||||
if line == 'eula=true':
|
||||
e_flag = True
|
||||
@ -227,7 +220,7 @@ class Server:
|
||||
else:
|
||||
e_flag = False
|
||||
|
||||
if e_flag == False:
|
||||
if not e_flag:
|
||||
if user_id:
|
||||
websocket_helper.broadcast_user(user_id, 'send_eula_bootbox', {
|
||||
'id': self.server_id
|
||||
@ -239,27 +232,24 @@ class Server:
|
||||
f.close()
|
||||
if helper.is_os_windows():
|
||||
logger.info("Windows Detected")
|
||||
creationflags=subprocess.CREATE_NEW_CONSOLE
|
||||
else:
|
||||
logger.info("Unix Detected")
|
||||
creationflags=None
|
||||
|
||||
logger.info("Starting server in {p} with command: {c}".format(p=self.server_path, c=self.server_command))
|
||||
logger.info(f"Starting server in {self.server_path} with command: {self.server_command}")
|
||||
|
||||
try:
|
||||
self.process = subprocess.Popen(self.server_command, cwd=self.server_path, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||
self.process = subprocess.Popen(
|
||||
self.server_command, cwd=self.server_path, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||
except Exception as ex:
|
||||
#Checks for java on initial fail
|
||||
if os.system("java -version") == 32512:
|
||||
msg = "Server {} failed to start with error code: {}".format(self.name, "Java not found. Please install Java then try again.")
|
||||
if user_id:
|
||||
websocket_helper.broadcast_user(user_id, 'send_start_error',{
|
||||
'error': translation.translate('error', 'noJava', user_lang).format(self.name)
|
||||
})
|
||||
return False
|
||||
else:
|
||||
msg = "Server {} failed to start with error code: {}".format(self.name, ex)
|
||||
logger.error(msg)
|
||||
logger.error(f"Server {self.name} failed to start with error code: {ex}")
|
||||
if user_id:
|
||||
websocket_helper.broadcast_user(user_id, 'send_start_error',{
|
||||
'error': translation.translate('error', 'start-error', user_lang).format(self.name, ex)
|
||||
@ -268,19 +258,20 @@ class Server:
|
||||
|
||||
out_buf = ServerOutBuf(self.process, self.server_id)
|
||||
|
||||
logger.debug('Starting virtual terminal listener for server {}'.format(self.name))
|
||||
threading.Thread(target=out_buf.check, daemon=True, name='{}_virtual_terminal'.format(self.server_id)).start()
|
||||
logger.debug(f'Starting virtual terminal listener for server {self.name}')
|
||||
threading.Thread(target=out_buf.check, daemon=True, name=f'{self.server_id}_virtual_terminal').start()
|
||||
|
||||
self.is_crashed = False
|
||||
|
||||
self.start_time = str(datetime.datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S'))
|
||||
|
||||
if self.process.poll() is None:
|
||||
logger.info("Server {} running with PID {}".format(self.name, self.process.pid))
|
||||
console.info("Server {} running with PID {}".format(self.name, self.process.pid))
|
||||
logger.info(f"Server {self.name} running with PID {self.process.pid}")
|
||||
console.info(f"Server {self.name} running with PID {self.process.pid}")
|
||||
self.is_crashed = False
|
||||
self.stats.record_stats()
|
||||
check_internet_thread = threading.Thread(target=self.check_internet_thread, daemon=True, args=(user_id, user_lang, ), name="{self.name}_Internet")
|
||||
check_internet_thread = threading.Thread(
|
||||
target=self.check_internet_thread, daemon=True, args=(user_id, user_lang, ), name=f"{self.name}_Internet")
|
||||
check_internet_thread.start()
|
||||
#Checks if this is the servers first run.
|
||||
if servers_helper.get_first_run(self.server_id):
|
||||
@ -301,14 +292,14 @@ class Server:
|
||||
websocket_helper.broadcast_user(user, 'send_start_reload', {
|
||||
})
|
||||
else:
|
||||
logger.warning("Server PID {} died right after starting - is this a server config issue?".format(self.process.pid))
|
||||
console.warning("Server PID {} died right after starting - is this a server config issue?".format(self.process.pid))
|
||||
logger.warning(f"Server PID {self.process.pid} died right after starting - is this a server config issue?")
|
||||
console.warning(f"Server PID {self.process.pid} died right after starting - is this a server config issue?")
|
||||
|
||||
if self.settings['crash_detection']:
|
||||
logger.info("Server {} has crash detection enabled - starting watcher task".format(self.name))
|
||||
console.info("Server {} has crash detection enabled - starting watcher task".format(self.name))
|
||||
logger.info(f"Server {self.name} has crash detection enabled - starting watcher task")
|
||||
console.info(f"Server {self.name} has crash detection enabled - starting watcher task")
|
||||
|
||||
self.crash_watcher_schedule = self.server_scheduler.add_job(self.detect_crash, 'interval', seconds=30, id="crash_watcher")
|
||||
self.server_scheduler.add_job(self.detect_crash, 'interval', seconds=30, id="c_{self.server_id}")
|
||||
|
||||
def check_internet_thread(self, user_id, user_lang):
|
||||
if user_id:
|
||||
@ -316,7 +307,6 @@ class Server:
|
||||
websocket_helper.broadcast_user(user_id, 'send_start_error', {
|
||||
'error': translation.translate('error', 'internet', user_lang)
|
||||
})
|
||||
return
|
||||
|
||||
def stop_threaded_server(self):
|
||||
self.stop_server()
|
||||
@ -332,8 +322,8 @@ class Server:
|
||||
self.process.terminate()
|
||||
running = self.check_running()
|
||||
if not running:
|
||||
logger.info("Can't stop server {} if it's not running".format(self.name))
|
||||
console.info("Can't stop server {} if it's not running".format(self.name))
|
||||
logger.info(f"Can't stop server {self.name} if it's not running")
|
||||
console.info(f"Can't stop server {self.name} if it's not running")
|
||||
return
|
||||
x = 0
|
||||
|
||||
@ -343,7 +333,7 @@ class Server:
|
||||
|
||||
while running:
|
||||
x = x+1
|
||||
logstr = "Server {} is still running - waiting 2s to see if it stops ({} seconds until force close)".format(server_name, int(60-(x*2)))
|
||||
logstr = f"Server {server_name} is still running - waiting 2s to see if it stops ({int(60-(x*2))} seconds until force close)"
|
||||
logger.info(logstr)
|
||||
console.info(logstr)
|
||||
running = self.check_running()
|
||||
@ -351,12 +341,12 @@ class Server:
|
||||
|
||||
# if we haven't closed in 60 seconds, let's just slam down on the PID
|
||||
if x >= 30:
|
||||
logger.info("Server {} is still running - Forcing the process down".format(server_name))
|
||||
console.info("Server {} is still running - Forcing the process down".format(server_name))
|
||||
logger.info(f"Server {server_name} is still running - Forcing the process down")
|
||||
console.info(f"Server {server_name} is still running - Forcing the process down")
|
||||
self.kill()
|
||||
|
||||
logger.info("Stopped Server {} with PID {}".format(server_name, server_pid))
|
||||
console.info("Stopped Server {} with PID {}".format(server_name, server_pid))
|
||||
logger.info(f"Stopped Server {server_name} with PID {server_pid}")
|
||||
console.info(f"Stopped Server {server_name} with PID {server_pid}")
|
||||
|
||||
# massive resetting of variables
|
||||
self.cleanup_server_object()
|
||||
@ -397,13 +387,13 @@ class Server:
|
||||
|
||||
def send_command(self, command):
|
||||
if not self.check_running() and command.lower() != 'start':
|
||||
logger.warning("Server not running, unable to send command \"{}\"".format(command))
|
||||
logger.warning(f"Server not running, unable to send command \"{command}\"")
|
||||
return False
|
||||
console.info("COMMAND TIME: {}".format(command))
|
||||
logger.debug("Sending command {} to server".format(command))
|
||||
console.info(f"COMMAND TIME: {command}")
|
||||
logger.debug(f"Sending command {command} to server")
|
||||
|
||||
# send it
|
||||
self.process.stdin.write("{}\n".format(command).encode('utf-8'))
|
||||
self.process.stdin.write(f"{command}\n".encode('utf-8'))
|
||||
self.process.stdin.flush()
|
||||
|
||||
def crash_detected(self, name):
|
||||
@ -412,28 +402,26 @@ class Server:
|
||||
self.remove_watcher_thread()
|
||||
|
||||
# the server crashed, or isn't found - so let's reset things.
|
||||
logger.warning("The server {} seems to have vanished unexpectedly, did it crash?".format(name))
|
||||
logger.warning(f"The server {name} seems to have vanished unexpectedly, did it crash?")
|
||||
|
||||
if self.settings['crash_detection']:
|
||||
logger.warning("The server {} has crashed and will be restarted. Restarting server".format(name))
|
||||
console.warning("The server {} has crashed and will be restarted. Restarting server".format(name))
|
||||
logger.warning(f"The server {name} has crashed and will be restarted. Restarting server")
|
||||
console.warning(f"The server {name} has crashed and will be restarted. Restarting server")
|
||||
self.run_threaded_server(None)
|
||||
return True
|
||||
else:
|
||||
logger.critical(
|
||||
"The server {} has crashed, crash detection is disabled and it will not be restarted".format(name))
|
||||
console.critical(
|
||||
"The server {} has crashed, crash detection is disabled and it will not be restarted".format(name))
|
||||
logger.critical(f"The server {name} has crashed, crash detection is disabled and it will not be restarted")
|
||||
console.critical(f"The server {name} has crashed, crash detection is disabled and it will not be restarted")
|
||||
return False
|
||||
|
||||
def kill(self):
|
||||
logger.info("Terminating server {} and all child processes".format(self.server_id))
|
||||
logger.info(f"Terminating server {self.server_id} and all child processes")
|
||||
process = psutil.Process(self.process.pid)
|
||||
|
||||
# for every sub process...
|
||||
for proc in process.children(recursive=True):
|
||||
# kill all the child processes - it sounds too wrong saying kill all the children (kevdagoat: lol!)
|
||||
logger.info("Sending SIGKILL to server {}".format(proc.name))
|
||||
logger.info(f"Sending SIGKILL to server {proc.name}")
|
||||
proc.kill()
|
||||
# kill the main process we are after
|
||||
logger.info('Sending SIGKILL to parent')
|
||||
@ -453,7 +441,7 @@ class Server:
|
||||
|
||||
def detect_crash(self):
|
||||
|
||||
logger.info("Detecting possible crash for server: {} ".format(self.name))
|
||||
logger.info(f"Detecting possible crash for server: {self.name} ")
|
||||
|
||||
running = self.check_running()
|
||||
|
||||
@ -473,11 +461,8 @@ class Server:
|
||||
|
||||
# we have tried to restart 4 times...
|
||||
elif self.restart_count == 4:
|
||||
logger.critical("Server {} has been restarted {} times. It has crashed, not restarting.".format(
|
||||
self.name, self.restart_count))
|
||||
|
||||
console.critical("Server {} has been restarted {} times. It has crashed, not restarting.".format(
|
||||
self.name, self.restart_count))
|
||||
logger.critical(f"Server {self.name} has been restarted {self.restart_count} times. It has crashed, not restarting.")
|
||||
console.critical(f"Server {self.name} has been restarted {self.restart_count} times. It has crashed, not restarting.")
|
||||
|
||||
# set to 99 restart attempts so this elif is skipped next time. (no double logging)
|
||||
self.restart_count = 99
|
||||
@ -489,13 +474,13 @@ class Server:
|
||||
def remove_watcher_thread(self):
|
||||
logger.info("Removing old crash detection watcher thread")
|
||||
console.info("Removing old crash detection watcher thread")
|
||||
self.crash_watcher_schedule.remove(self.server_name)
|
||||
self.server_scheduler.remove_job('c_'+str(self.server_id))
|
||||
|
||||
def agree_eula(self, user_id):
|
||||
file = os.path.join(self.server_path, 'eula.txt')
|
||||
f = open(file, 'w')
|
||||
f = open(file, 'w', encoding='utf-8')
|
||||
f.write('eula=true')
|
||||
f.close
|
||||
f.close()
|
||||
self.run_threaded_server(user_id)
|
||||
|
||||
def is_backup_running(self):
|
||||
@ -506,8 +491,8 @@ class Server:
|
||||
|
||||
def backup_server(self):
|
||||
backup_thread = threading.Thread(target=self.a_backup_server, daemon=True, name=f"backup_{self.name}")
|
||||
logger.info("Starting Backup Thread for server {}.".format(self.settings['server_name']))
|
||||
if self.server_path == None:
|
||||
logger.info(f"Starting Backup Thread for server {self.settings['server_name']}.")
|
||||
if self.server_path is None:
|
||||
self.server_path = helper.get_os_understandable_path(self.settings['path'])
|
||||
logger.info("Backup Thread - Local server path not defined. Setting local server path variable.")
|
||||
#checks if the backup thread is currently alive for this server
|
||||
@ -515,44 +500,50 @@ class Server:
|
||||
try:
|
||||
backup_thread.start()
|
||||
except Exception as ex:
|
||||
logger.error("Failed to start backup: {}".format(ex))
|
||||
logger.error(f"Failed to start backup: {ex}")
|
||||
return False
|
||||
else:
|
||||
logger.error("Backup is already being processed for server {}. Canceling backup request".format(self.settings['server_name']))
|
||||
logger.error(f"Backup is already being processed for server {self.settings['server_name']}. Canceling backup request")
|
||||
return False
|
||||
logger.info("Backup Thread started for server {}.".format(self.settings['server_name']))
|
||||
logger.info(f"Backup Thread started for server {self.settings['server_name']}.")
|
||||
|
||||
def a_backup_server(self):
|
||||
logger.info("Starting server {} (ID {}) backup".format(self.name, self.server_id))
|
||||
logger.info(f"Starting server {self.name} (ID {self.server_id}) backup")
|
||||
self.is_backingup = True
|
||||
conf = management_helper.get_backup_config(self.server_id)
|
||||
try:
|
||||
backup_filename = "{}/{}".format(self.settings['backup_path'], datetime.datetime.now().strftime('%Y-%m-%d_%H-%M-%S'))
|
||||
logger.info("Creating backup of server '{}' (ID#{}, path={}) at '{}'".format(self.settings['server_name'], self.server_id, self.server_path, backup_filename))
|
||||
backup_filename = f"{self.settings['backup_path']}/{datetime.datetime.now().strftime('%Y-%m-%d_%H-%M-%S')}"
|
||||
logger.info(f"Creating backup of server '{self.settings['server_name']}'" +
|
||||
f" (ID#{self.server_id}, path={self.server_path}) at '{backup_filename}'")
|
||||
shutil.make_archive(helper.get_os_understandable_path(backup_filename), 'zip', self.server_path)
|
||||
while len(self.list_backups()) > conf["max_backups"] and conf["max_backups"] > 0:
|
||||
backup_list = self.list_backups()
|
||||
oldfile = backup_list[0]
|
||||
oldfile_path = "{}/{}".format(conf['backup_path'], oldfile['path'])
|
||||
logger.info("Removing old backup '{}'".format(oldfile['path']))
|
||||
oldfile_path = f"{conf['backup_path']}/{oldfile['path']}"
|
||||
logger.info(f"Removing old backup '{oldfile['path']}'")
|
||||
os.remove(helper.get_os_understandable_path(oldfile_path))
|
||||
self.is_backingup = False
|
||||
logger.info("Backup of server: {} completed".format(self.name))
|
||||
logger.info(f"Backup of server: {self.name} completed")
|
||||
return
|
||||
except:
|
||||
logger.exception("Failed to create backup of server {} (ID {})".format(self.name, self.server_id))
|
||||
logger.exception(f"Failed to create backup of server {self.name} (ID {self.server_id})")
|
||||
self.is_backingup = False
|
||||
return
|
||||
|
||||
def list_backups(self):
|
||||
if self.settings['backup_path']:
|
||||
if helper.check_path_exists(helper.get_os_understandable_path(self.settings['backup_path'])):
|
||||
files = helper.get_human_readable_files_sizes(helper.list_dir_by_date(helper.get_os_understandable_path(self.settings['backup_path'])))
|
||||
return [{"path": os.path.relpath(f['path'], start=helper.get_os_understandable_path(self.settings['backup_path'])), "size": f["size"]} for f in files]
|
||||
files = (
|
||||
helper.get_human_readable_files_sizes(helper.list_dir_by_date(helper.get_os_understandable_path(self.settings['backup_path']))))
|
||||
return [{
|
||||
"path": os.path.relpath(f['path'],
|
||||
start=helper.get_os_understandable_path(self.settings['backup_path'])),
|
||||
"size": f["size"]
|
||||
} for f in files]
|
||||
else:
|
||||
return []
|
||||
else:
|
||||
logger.info("Error putting backup file list for server with ID: {}".format(self.server_id))
|
||||
logger.info(f"Error putting backup file list for server with ID: {self.server_id}")
|
||||
return[]
|
||||
|
||||
def jar_update(self):
|
||||
@ -567,13 +558,12 @@ class Server:
|
||||
return False
|
||||
|
||||
def a_jar_update(self):
|
||||
error = False
|
||||
wasStarted = "-1"
|
||||
self.backup_server()
|
||||
#checks if server is running. Calls shutdown if it is running.
|
||||
if self.check_running():
|
||||
wasStarted = True
|
||||
logger.info("Server with PID {} is running. Sending shutdown command".format(self.process.pid))
|
||||
logger.info(f"Server with PID {self.process.pid} is running. Sending shutdown command")
|
||||
self.stop_threaded_server()
|
||||
else:
|
||||
wasStarted = False
|
||||
@ -594,17 +584,17 @@ class Server:
|
||||
if os.path.isdir(backup_dir):
|
||||
backup_executable = os.path.join(backup_dir, 'old_server.jar')
|
||||
else:
|
||||
logger.info("Executable backup directory not found for Server: {}. Creating one.".format(self.name))
|
||||
logger.info(f"Executable backup directory not found for Server: {self.name}. Creating one.")
|
||||
os.mkdir(backup_dir)
|
||||
backup_executable = os.path.join(backup_dir, 'old_server.jar')
|
||||
|
||||
if os.path.isfile(backup_executable):
|
||||
#removes old backup
|
||||
logger.info("Old backup found for server: {}. Removing...".format(self.name))
|
||||
logger.info(f"Old backup found for server: {self.name}. Removing...")
|
||||
os.remove(backup_executable)
|
||||
logger.info("Old backup removed for server: {}.".format(self.name))
|
||||
logger.info(f"Old backup removed for server: {self.name}.")
|
||||
else:
|
||||
logger.info("No old backups found for server: {}".format(self.name))
|
||||
logger.info(f"No old backups found for server: {self.name}")
|
||||
|
||||
current_executable = os.path.join(helper.get_os_understandable_path(self.settings['path']), self.settings['executable'])
|
||||
|
||||
@ -637,7 +627,8 @@ class Server:
|
||||
for user in server_users:
|
||||
websocket_helper.broadcast_user(user, 'notification', "Executable update finished for "+self.name)
|
||||
|
||||
management_helper.add_to_audit_log_raw('Alert', '-1', self.server_id, "Executable update finished for "+self.name, self.settings['server_ip'])
|
||||
management_helper.add_to_audit_log_raw(
|
||||
'Alert', '-1', self.server_id, "Executable update finished for "+self.name, self.settings['server_ip'])
|
||||
if wasStarted:
|
||||
self.start_server()
|
||||
elif not downloaded and not self.is_backingup:
|
||||
@ -647,4 +638,3 @@ class Server:
|
||||
websocket_helper.broadcast_user(user,'notification',
|
||||
"Executable update failed for " + self.name + ". Check log file for details.")
|
||||
logger.error("Executable download failed.")
|
||||
pass
|
||||
|
@ -1,36 +1,32 @@
|
||||
from datetime import timedelta
|
||||
from http import server
|
||||
import os
|
||||
import sys
|
||||
import json
|
||||
import time
|
||||
import logging
|
||||
import threading
|
||||
import asyncio
|
||||
import shutil
|
||||
from tzlocal import get_localzone
|
||||
|
||||
from app.classes.controllers.users_controller import Users_Controller
|
||||
|
||||
from app.classes.shared.helpers import helper
|
||||
from app.classes.shared.console import console
|
||||
from app.classes.web.tornado import Webserver
|
||||
|
||||
from app.classes.web.tornado_handler import Webserver
|
||||
from app.classes.web.websocket_helper import websocket_helper
|
||||
|
||||
from app.classes.minecraft.serverjars import server_jar_obj
|
||||
from app.classes.models.servers import servers_helper
|
||||
from app.classes.models.management import management_helper
|
||||
from apscheduler.events import EVENT_JOB_ERROR, EVENT_JOB_EXECUTED, EVENT_ALL, EVENT_JOB_REMOVED
|
||||
from app.classes.controllers.users_controller import Users_Controller
|
||||
from app.classes.controllers.servers_controller import Servers_Controller
|
||||
|
||||
logger = logging.getLogger('apscheduler')
|
||||
|
||||
try:
|
||||
from apscheduler.events import EVENT_JOB_EXECUTED
|
||||
from apscheduler.schedulers.background import BackgroundScheduler
|
||||
from apscheduler.triggers.cron import CronTrigger
|
||||
|
||||
except ModuleNotFoundError as e:
|
||||
logger.critical("Import Error: Unable to load {} module".format(e.name), exc_info=True)
|
||||
console.critical("Import Error: Unable to load {} module".format(e.name))
|
||||
except ModuleNotFoundError as err:
|
||||
logger.critical(f"Import Error: Unable to load {err.name} module", exc_info=True)
|
||||
console.critical(f"Import Error: Unable to load {err.name} module")
|
||||
sys.exit(1)
|
||||
|
||||
scheduler_intervals = { 'seconds',
|
||||
@ -80,7 +76,7 @@ class TasksManager:
|
||||
jobs = management_helper.get_schedules_enabled()
|
||||
logger.info("Reload from DB called. Current enabled schedules: ")
|
||||
for item in jobs:
|
||||
logger.info("JOB: {}".format(item))
|
||||
logger.info(f"JOB: {item}")
|
||||
|
||||
def command_watcher(self):
|
||||
while True:
|
||||
@ -164,54 +160,133 @@ class TasksManager:
|
||||
for schedule in schedules:
|
||||
if schedule.cron_string != "":
|
||||
try:
|
||||
self.scheduler.add_job(management_helper.add_command, CronTrigger.from_crontab(schedule.cron_string, timezone=str(self.tz)), id=str(schedule.schedule_id), args=[schedule.server_id, self.users_controller.get_id_by_name('system'), '127.0.0.1', schedule.command])
|
||||
self.scheduler.add_job(management_helper.add_command,
|
||||
CronTrigger.from_crontab(schedule.cron_string,
|
||||
timezone=str(self.tz)),
|
||||
id = str(schedule.schedule_id),
|
||||
args = [schedule.server_id,
|
||||
self.users_controller.get_id_by_name('system'),
|
||||
'127.0.0.1',
|
||||
schedule.command]
|
||||
)
|
||||
except Exception as e:
|
||||
console.error("Failed to schedule task with error: {}.".format(e))
|
||||
console.error(f"Failed to schedule task with error: {e}.")
|
||||
console.warning("Removing failed task from DB.")
|
||||
logger.error("Failed to schedule task with error: {}.".format(e))
|
||||
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)
|
||||
else:
|
||||
if schedule.interval_type == 'hours':
|
||||
self.scheduler.add_job(management_helper.add_command, 'cron', minute = 0, hour = '*/'+str(schedule.interval), id=str(schedule.schedule_id), args=[schedule.server_id, self.users_controller.get_id_by_name('system'), '127.0.0.1', schedule.command])
|
||||
self.scheduler.add_job(management_helper.add_command,
|
||||
'cron',
|
||||
minute = 0,
|
||||
hour = '*/'+str(schedule.interval),
|
||||
id = str(schedule.schedule_id),
|
||||
args = [schedule.server_id,
|
||||
self.users_controller.get_id_by_name('system'),
|
||||
'127.0.0.1',
|
||||
schedule.command]
|
||||
)
|
||||
elif schedule.interval_type == 'minutes':
|
||||
self.scheduler.add_job(management_helper.add_command, 'cron', minute = '*/'+str(schedule.interval), id=str(schedule.schedule_id), args=[schedule.server_id, self.users_controller.get_id_by_name('system'), '127.0.0.1', schedule.command])
|
||||
self.scheduler.add_job(management_helper.add_command,
|
||||
'cron',
|
||||
minute = '*/'+str(schedule.interval),
|
||||
id = str(schedule.schedule_id),
|
||||
args = [schedule.server_id,
|
||||
self.users_controller.get_id_by_name('system'),
|
||||
'127.0.0.1',
|
||||
schedule.command]
|
||||
)
|
||||
elif schedule.interval_type == 'days':
|
||||
time = schedule.start_time.split(':')
|
||||
self.scheduler.add_job(management_helper.add_command, 'cron', day = '*/'+str(schedule.interval), hour=time[0], minute=time[1], id=str(schedule.schedule_id), args=[schedule.server_id, self.users_controller.get_id_by_name('system'), '127.0.0.1', schedule.command])
|
||||
|
||||
curr_time = schedule.start_time.split(':')
|
||||
self.scheduler.add_job(management_helper.add_command,
|
||||
'cron',
|
||||
day = '*/'+str(schedule.interval),
|
||||
hour=curr_time[0],
|
||||
minute=curr_time[1],
|
||||
id=str(schedule.schedule_id),
|
||||
args=[schedule.server_id,
|
||||
self.users_controller.get_id_by_name('system'),
|
||||
'127.0.0.1',
|
||||
schedule.command]
|
||||
)
|
||||
self.scheduler.start()
|
||||
jobs = self.scheduler.get_jobs()
|
||||
logger.info("Loaded schedules. Current enabled schedules: ")
|
||||
for item in jobs:
|
||||
logger.info("JOB: {}".format(item))
|
||||
logger.info(f"JOB: {item}")
|
||||
|
||||
def schedule_job(self, job_data):
|
||||
sch_id = management_helper.create_scheduled_task(job_data['server_id'], job_data['action'], job_data['interval'], job_data['interval_type'], job_data['start_time'], job_data['command'], "None", job_data['enabled'], job_data['one_time'], job_data['cron_string'])
|
||||
sch_id = management_helper.create_scheduled_task(
|
||||
job_data['server_id'],
|
||||
job_data['action'],
|
||||
job_data['interval'],
|
||||
job_data['interval_type'],
|
||||
job_data['start_time'],
|
||||
job_data['command'],
|
||||
"None",
|
||||
job_data['enabled'],
|
||||
job_data['one_time'],
|
||||
job_data['cron_string'])
|
||||
if job_data['enabled']:
|
||||
if job_data['cron_string'] != "":
|
||||
try:
|
||||
self.scheduler.add_job(management_helper.add_command, CronTrigger.from_crontab(job_data['cron_string'], timezone=str(self.tz)), id=str(sch_id), args=[job_data['server_id'], self.users_controller.get_id_by_name('system'), '127.0.0.1', job_data['command']])
|
||||
self.scheduler.add_job(management_helper.add_command,
|
||||
CronTrigger.from_crontab(job_data['cron_string'],
|
||||
timezone=str(self.tz)),
|
||||
id=str(sch_id),
|
||||
args=[job_data['server_id'],
|
||||
self.users_controller.get_id_by_name('system'),
|
||||
'127.0.0.1',
|
||||
job_data['command']]
|
||||
)
|
||||
except Exception as e:
|
||||
console.error("Failed to schedule task with error: {}.".format(e))
|
||||
console.error(f"Failed to schedule task with error: {e}.")
|
||||
console.warning("Removing failed task from DB.")
|
||||
logger.error("Failed to schedule task with error: {}.".format(e))
|
||||
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)
|
||||
else:
|
||||
if job_data['interval_type'] == 'hours':
|
||||
self.scheduler.add_job(management_helper.add_command, 'cron', minute = 0, hour = '*/'+str(job_data['interval']), id=str(sch_id), args=[job_data['server_id'], self.users_controller.get_id_by_name('system'), '127.0.0.1', job_data['command']])
|
||||
self.scheduler.add_job(management_helper.add_command,
|
||||
'cron',
|
||||
minute = 0,
|
||||
hour = '*/'+str(job_data['interval']),
|
||||
id=str(sch_id),
|
||||
args=[job_data['server_id'],
|
||||
self.users_controller.get_id_by_name('system'),
|
||||
'127.0.0.1',
|
||||
job_data['command']]
|
||||
)
|
||||
elif job_data['interval_type'] == 'minutes':
|
||||
self.scheduler.add_job(management_helper.add_command, 'cron', minute = '*/'+str(job_data['interval']), id=str(sch_id), args=[job_data['server_id'], self.users_controller.get_id_by_name('system'), '127.0.0.1', job_data['command']])
|
||||
self.scheduler.add_job(management_helper.add_command,
|
||||
'cron',
|
||||
minute = '*/'+str(job_data['interval']),
|
||||
id=str(sch_id),
|
||||
args=[job_data['server_id'],
|
||||
self.users_controller.get_id_by_name('system'),
|
||||
'127.0.0.1',
|
||||
job_data['command']]
|
||||
)
|
||||
elif job_data['interval_type'] == 'days':
|
||||
time = job_data['start_time'].split(':')
|
||||
self.scheduler.add_job(management_helper.add_command, 'cron', day = '*/'+str(job_data['interval']), hour = time[0], minute = time[1], id=str(sch_id), args=[job_data['server_id'], self.users_controller.get_id_by_name('system'), '127.0.0.1', job_data['command']], )
|
||||
curr_time = job_data['start_time'].split(':')
|
||||
self.scheduler.add_job(management_helper.add_command,
|
||||
'cron',
|
||||
day = '*/'+str(job_data['interval']),
|
||||
hour = curr_time[0],
|
||||
minute = curr_time[1],
|
||||
id=str(sch_id),
|
||||
args=[job_data['server_id'],
|
||||
self.users_controller.get_id_by_name('system'),
|
||||
'127.0.0.1',
|
||||
job_data['command']],
|
||||
)
|
||||
logger.info("Added job. Current enabled schedules: ")
|
||||
jobs = self.scheduler.get_jobs()
|
||||
for item in jobs:
|
||||
logger.info("JOB: {}".format(item))
|
||||
logger.info(f"JOB: {item}")
|
||||
|
||||
def remove_all_server_tasks(self, server_id):
|
||||
schedules = management_helper.get_schedules_by_server(server_id)
|
||||
@ -223,9 +298,10 @@ class TasksManager:
|
||||
management_helper.delete_scheduled_task(sch_id)
|
||||
if job.enabled:
|
||||
self.scheduler.remove_job(str(sch_id))
|
||||
logger.info("Job with ID {} was deleted.".format(sch_id))
|
||||
logger.info(f"Job with ID {sch_id} was deleted.")
|
||||
else:
|
||||
logger.info("Job with ID {} was deleted from DB, but was not enabled. Not going to try removing something that doesn't exist from active schedules.".format(sch_id))
|
||||
logger.info(f"Job with ID {sch_id} was deleted from DB, but was not enabled."
|
||||
+ "Not going to try removing something that doesn't exist from active schedules.")
|
||||
|
||||
def update_job(self, sch_id, job_data):
|
||||
management_helper.update_scheduled_task(sch_id, job_data)
|
||||
@ -233,28 +309,64 @@ class TasksManager:
|
||||
self.scheduler.remove_job(str(sch_id))
|
||||
except:
|
||||
logger.info("No job found in update job. Assuming it was previously disabled. Starting new job.")
|
||||
|
||||
if job_data['enabled']:
|
||||
if job_data['cron_string'] != "":
|
||||
cron = job_data['cron_string'].split(' ')
|
||||
try:
|
||||
self.scheduler.add_job(management_helper.add_command, 'cron', minute = cron[0], hour = cron[1], day = cron[2], month = cron[3], day_of_week = cron[4], args=[job_data['server_id'], self.users_controller.get_id_by_name('system'), '127.0.0.1', job_data['command']])
|
||||
self.scheduler.add_job(management_helper.add_command,
|
||||
CronTrigger.from_crontab(job_data['cron_string'],
|
||||
timezone=str(self.tz)),
|
||||
id=str(sch_id),
|
||||
args=[job_data['server_id'],
|
||||
self.users_controller.get_id_by_name('system'),
|
||||
'127.0.0.1',
|
||||
job_data['command']]
|
||||
)
|
||||
except Exception as e:
|
||||
console.error("Failed to schedule task with error: {}.".format(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)
|
||||
else:
|
||||
if job_data['interval_type'] == 'hours':
|
||||
self.scheduler.add_job(management_helper.add_command, 'cron', minute = 0, hour = '*/'+str(job_data['interval']), id=str(sch_id), args=[job_data['server_id'], self.users_controller.get_id_by_name('system'), '127.0.0.1', job_data['command']])
|
||||
self.scheduler.add_job(management_helper.add_command,
|
||||
'cron',
|
||||
minute = 0,
|
||||
hour = '*/'+str(job_data['interval']),
|
||||
id=str(sch_id),
|
||||
args=[job_data['server_id'],
|
||||
self.users_controller.get_id_by_name('system'),
|
||||
'127.0.0.1',
|
||||
job_data['command']]
|
||||
)
|
||||
elif job_data['interval_type'] == 'minutes':
|
||||
self.scheduler.add_job(management_helper.add_command, 'cron', minute = '*/'+str(job_data['interval']), id=str(sch_id), args=[job_data['server_id'], self.users_controller.get_id_by_name('system'), '127.0.0.1', job_data['command']])
|
||||
self.scheduler.add_job(management_helper.add_command,
|
||||
'cron',
|
||||
minute = '*/'+str(job_data['interval']),
|
||||
id=str(sch_id),
|
||||
args=[job_data['server_id'],
|
||||
self.users_controller.get_id_by_name('system'),
|
||||
'127.0.0.1',
|
||||
job_data['command']]
|
||||
)
|
||||
elif job_data['interval_type'] == 'days':
|
||||
time = job_data['start_time'].split(':')
|
||||
self.scheduler.add_job(management_helper.add_command, 'cron', day = '*/'+str(job_data['interval']), hour = time[0], minute = time[1], id=str(sch_id), args=[job_data['server_id'], self.users_controller.get_id_by_name('system'), '127.0.0.1', job_data['command']], )
|
||||
curr_time = job_data['start_time'].split(':')
|
||||
self.scheduler.add_job(management_helper.add_command,
|
||||
'cron',
|
||||
day = '*/'+str(job_data['interval']),
|
||||
hour = curr_time[0],
|
||||
minute = curr_time[1],
|
||||
id=str(sch_id),
|
||||
args=[job_data['server_id'],
|
||||
self.users_controller.get_id_by_name('system'),
|
||||
'127.0.0.1',
|
||||
job_data['command']]
|
||||
)
|
||||
else:
|
||||
try:
|
||||
self.scheduler.get_job(str(sch_id))
|
||||
self.scheduler.remove_job(str(sch_id))
|
||||
except:
|
||||
logger.info("APScheduler found no scheduled job on schedule update for schedule with id: {}. Assuming it was already disabled.".format(sch_id))
|
||||
logger.info(f"APScheduler found no scheduled job on schedule update for schedule with id: {sch_id} Assuming it was already disabled.")
|
||||
|
||||
def schedule_watcher(self, event):
|
||||
if not event.exception:
|
||||
@ -266,12 +378,12 @@ class TasksManager:
|
||||
else:
|
||||
logger.info("Event job ID is not numerical. Assuming it's stats - not stored in DB. Moving on.")
|
||||
else:
|
||||
logger.error("Task failed with error: {}".format(event.exception))
|
||||
logger.error(f"Task failed with error: {event.exception}")
|
||||
|
||||
def start_stats_recording(self):
|
||||
stats_update_frequency = helper.get_setting('stats_update_frequency')
|
||||
logger.info("Stats collection frequency set to {stats} seconds".format(stats=stats_update_frequency))
|
||||
console.info("Stats collection frequency set to {stats} seconds".format(stats=stats_update_frequency))
|
||||
logger.info(f"Stats collection frequency set to {stats_update_frequency} seconds")
|
||||
console.info(f"Stats collection frequency set to {stats_update_frequency} seconds")
|
||||
|
||||
# one for now,
|
||||
self.controller.stats.record_stats()
|
||||
@ -312,14 +424,17 @@ class TasksManager:
|
||||
'mem_usage': host_stats.get('mem_usage')
|
||||
})
|
||||
|
||||
servers = self.controller.servers_list
|
||||
for user in Users_Controller.get_all_users():
|
||||
servers_ping = []
|
||||
if user.superuser:
|
||||
servers = Servers_Controller.get_all_servers_stats()
|
||||
else:
|
||||
servers = Servers_Controller.get_authorized_servers_stats(user.user_id)
|
||||
for srv in servers:
|
||||
server_data = srv.get('server_data_obj', False)
|
||||
if server_data:
|
||||
server_id = server_data.get('server_id', False)
|
||||
if srv:
|
||||
server_id = srv['server_data']['server_id']
|
||||
srv['raw_ping_result'] = self.controller.stats.get_raw_server_stats(server_id)
|
||||
if ("{}".format(srv['raw_ping_result'].get('icon')) == "b''"):
|
||||
if f"{srv['raw_ping_result'].get('icon')}" == "b''":
|
||||
srv['raw_ping_result']['icon'] = False
|
||||
|
||||
servers_ping.append({
|
||||
@ -340,12 +455,12 @@ class TasksManager:
|
||||
'version': srv['raw_ping_result'].get('version'),
|
||||
'icon': srv['raw_ping_result'].get('icon')
|
||||
})
|
||||
if (len(websocket_helper.clients) > 0):
|
||||
websocket_helper.broadcast_page_params(
|
||||
if len(websocket_helper.clients) > 0:
|
||||
websocket_helper.broadcast_user_page_params(
|
||||
'/panel/server_detail',
|
||||
{
|
||||
'id': str(server_id)
|
||||
},
|
||||
}, user.user_id,
|
||||
'update_server_details',
|
||||
{
|
||||
'id': srv['raw_ping_result'].get('id'),
|
||||
@ -369,7 +484,7 @@ class TasksManager:
|
||||
|
||||
if (len(servers_ping) > 0) & (len(websocket_helper.clients) > 0):
|
||||
try:
|
||||
websocket_helper.broadcast_page('/panel/dashboard', 'update_server_status', servers_ping)
|
||||
websocket_helper.broadcast_user_page('/panel/dashboard', user.user_id, 'update_server_status', servers_ping)
|
||||
websocket_helper.broadcast_page('/status', 'update_server_status', servers_ping)
|
||||
except:
|
||||
console.warning("Can't broadcast server status to websocket")
|
||||
@ -378,4 +493,3 @@ class TasksManager:
|
||||
def log_watcher(self):
|
||||
self.controller.servers.check_for_old_logs()
|
||||
self.scheduler.add_job(self.controller.servers.check_for_old_logs, 'interval', hours=6, id="log-mgmt")
|
||||
|
||||
|
@ -8,7 +8,6 @@ from app.classes.shared.helpers import helper
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Translation:
|
||||
def __init__(self):
|
||||
self.translations_path = os.path.join(helper.root_dir, 'app', 'translations')
|
||||
@ -55,8 +54,8 @@ class Translation:
|
||||
try:
|
||||
translated_page = data[page]
|
||||
except KeyError:
|
||||
logger.error('Translation File Error: page {} does not exist for lang {}'.format(page, language))
|
||||
console.error('Translation File Error: page {} does not exist for lang {}'.format(page, language))
|
||||
logger.error(f'Translation File Error: page {page} does not exist for lang {language}')
|
||||
console.error(f'Translation File Error: page {page} does not exist for lang {language}')
|
||||
return None
|
||||
|
||||
try:
|
||||
|
@ -1,24 +1,17 @@
|
||||
import json
|
||||
import logging
|
||||
import tempfile
|
||||
import threading
|
||||
from typing import Container
|
||||
import zipfile
|
||||
|
||||
import tornado.web
|
||||
import tornado.escape
|
||||
import bleach
|
||||
import os
|
||||
import shutil
|
||||
import html
|
||||
import re
|
||||
from app.classes.models.users import helper_users
|
||||
import logging
|
||||
import tornado.web
|
||||
import tornado.escape
|
||||
import bleach
|
||||
|
||||
from app.classes.shared.console import console
|
||||
from app.classes.shared.main_models import Users, installer
|
||||
from app.classes.web.base_handler import BaseHandler
|
||||
from app.classes.shared.helpers import helper
|
||||
from app.classes.shared.server import ServerOutBuf
|
||||
|
||||
from app.classes.web.base_handler import BaseHandler
|
||||
from app.classes.models.server_permissions import Enum_Permissions_Server
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@ -67,7 +60,7 @@ class AjaxHandler(BaseHandler):
|
||||
return
|
||||
|
||||
if not server_data['log_path']:
|
||||
logger.warning("Log path not found in server_log ajax call ({})".format(server_id))
|
||||
logger.warning(f"Log path not found in server_log ajax call ({server_id})")
|
||||
|
||||
if full_log:
|
||||
log_lines = helper.get_setting('max_log_lines')
|
||||
@ -81,12 +74,11 @@ class AjaxHandler(BaseHandler):
|
||||
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))
|
||||
self.write('{}<br />'.format(line))
|
||||
self.write(f'{line}<br />')
|
||||
# self.write(d.encode("utf-8"))
|
||||
|
||||
except Exception as e:
|
||||
logger.warning("Skipping Log Line due to error: {}".format(e))
|
||||
pass
|
||||
logger.warning(f"Skipping Log Line due to error: {e}")
|
||||
|
||||
elif page == "announcements":
|
||||
data = helper.get_announcements()
|
||||
@ -97,20 +89,22 @@ class AjaxHandler(BaseHandler):
|
||||
file_path = helper.get_os_understandable_path(self.get_argument('file_path', None))
|
||||
server_id = self.get_argument('id', None)
|
||||
|
||||
if not self.check_server_id(server_id, 'get_file'): return
|
||||
else: server_id = bleach.clean(server_id)
|
||||
if not self.check_server_id(server_id, 'get_file'):
|
||||
return
|
||||
else:
|
||||
server_id = bleach.clean(server_id)
|
||||
|
||||
if not helper.in_path(helper.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)):
|
||||
logger.warning("Invalid path in get_file ajax call ({})".format(file_path))
|
||||
console.warning("Invalid path in get_file ajax call ({})".format(file_path))
|
||||
logger.warning(f"Invalid path in get_file ajax call ({file_path})")
|
||||
console.warning(f"Invalid path in get_file ajax call ({file_path})")
|
||||
return
|
||||
|
||||
|
||||
error = None
|
||||
|
||||
try:
|
||||
with open(file_path) as file:
|
||||
with open(file_path, encoding='utf-8') as file:
|
||||
file_contents = file.read()
|
||||
except UnicodeDecodeError:
|
||||
file_contents = ''
|
||||
@ -126,8 +120,10 @@ class AjaxHandler(BaseHandler):
|
||||
server_id = self.get_argument('id', None)
|
||||
path = self.get_argument('path', None)
|
||||
|
||||
if not self.check_server_id(server_id, 'get_tree'): return
|
||||
else: server_id = bleach.clean(server_id)
|
||||
if not self.check_server_id(server_id, 'get_tree'):
|
||||
return
|
||||
else:
|
||||
server_id = bleach.clean(server_id)
|
||||
|
||||
if helper.validate_traversal(self.controller.servers.get_server_data_by_id(server_id)['path'], path):
|
||||
self.write(helper.get_os_understandable_path(path) + '\n' +
|
||||
@ -154,8 +150,10 @@ class AjaxHandler(BaseHandler):
|
||||
server_id = self.get_argument('id', None)
|
||||
path = self.get_argument('path', None)
|
||||
|
||||
if not self.check_server_id(server_id, 'get_tree'): return
|
||||
else: server_id = bleach.clean(server_id)
|
||||
if not self.check_server_id(server_id, 'get_tree'):
|
||||
return
|
||||
else:
|
||||
server_id = bleach.clean(server_id)
|
||||
|
||||
if helper.validate_traversal(self.controller.servers.get_server_data_by_id(server_id)['path'], path):
|
||||
self.write(helper.get_os_understandable_path(path) + '\n' +
|
||||
@ -182,12 +180,6 @@ class AjaxHandler(BaseHandler):
|
||||
'Players': Enum_Permissions_Server.Players,
|
||||
}
|
||||
user_perms = self.controller.server_perms.get_user_id_permissions_list(exec_user['user_id'], server_id)
|
||||
error = bleach.clean(self.get_argument('error', "WTF Error!"))
|
||||
|
||||
page_data = {
|
||||
'user_data': exec_user,
|
||||
'error': error
|
||||
}
|
||||
|
||||
if page == "send_command":
|
||||
command = self.get_body_argument('command', default=None, strip=True)
|
||||
@ -200,18 +192,23 @@ class AjaxHandler(BaseHandler):
|
||||
srv_obj = self.controller.get_server_obj(server_id)
|
||||
|
||||
if command == srv_obj.settings['stop_command']:
|
||||
logger.info("Stop command detected as terminal input - intercepting. Starting Crafty's stop process for server with id: {}.".format(server_id))
|
||||
logger.info("Stop command detected as terminal input - intercepting." +
|
||||
f"Starting Crafty's stop process for server with id: {server_id}")
|
||||
self.controller.management.send_command(exec_user['user_id'], server_id, self.get_remote_ip(), 'stop_server')
|
||||
command = None
|
||||
elif command == 'restart':
|
||||
logger.info("Restart command detected as terminal input - intercepting. Starting Crafty's stop process for server with id: {}.".format(server_id))
|
||||
logger.info("Restart command detected as terminal input - intercepting." +
|
||||
f"Starting Crafty's stop process for server with id: {server_id}")
|
||||
self.controller.management.send_command(exec_user['user_id'], server_id, self.get_remote_ip(), 'restart_server')
|
||||
command = None
|
||||
if command:
|
||||
if srv_obj.check_running():
|
||||
srv_obj.send_command(command)
|
||||
|
||||
self.controller.management.add_to_audit_log(exec_user['user_id'], "Sent command to {} terminal: {}".format(self.controller.servers.get_server_friendly_name(server_id), command), server_id, self.get_remote_ip())
|
||||
self.controller.management.add_to_audit_log(exec_user['user_id'],
|
||||
f"Sent command to {self.controller.servers.get_server_friendly_name(server_id)} terminal: {command}",
|
||||
server_id,
|
||||
self.get_remote_ip())
|
||||
|
||||
elif page == "create_file":
|
||||
if not permissions['Files'] in user_perms:
|
||||
@ -223,17 +220,19 @@ class AjaxHandler(BaseHandler):
|
||||
file_path = os.path.join(file_parent, file_name)
|
||||
server_id = self.get_argument('id', None)
|
||||
|
||||
if not self.check_server_id(server_id, 'create_file'): return
|
||||
else: server_id = bleach.clean(server_id)
|
||||
if not self.check_server_id(server_id, 'create_file'):
|
||||
return
|
||||
else:
|
||||
server_id = bleach.clean(server_id)
|
||||
|
||||
if not helper.in_path(helper.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)):
|
||||
logger.warning("Invalid path in create_file ajax call ({})".format(file_path))
|
||||
console.warning("Invalid path in create_file ajax call ({})".format(file_path))
|
||||
logger.warning(f"Invalid path in create_file ajax call ({file_path})")
|
||||
console.warning(f"Invalid path in create_file ajax call ({file_path})")
|
||||
return
|
||||
|
||||
# Create the file by opening it
|
||||
with open(file_path, 'w') as file_object:
|
||||
with open(file_path, 'w', encoding='utf-8') as file_object:
|
||||
file_object.close()
|
||||
|
||||
elif page == "create_dir":
|
||||
@ -246,13 +245,15 @@ class AjaxHandler(BaseHandler):
|
||||
dir_path = os.path.join(dir_parent, dir_name)
|
||||
server_id = self.get_argument('id', None)
|
||||
|
||||
if not self.check_server_id(server_id, 'create_dir'): return
|
||||
else: server_id = bleach.clean(server_id)
|
||||
if not self.check_server_id(server_id, 'create_dir'):
|
||||
return
|
||||
else:
|
||||
server_id = bleach.clean(server_id)
|
||||
|
||||
if not helper.in_path(helper.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)):
|
||||
logger.warning("Invalid path in create_dir ajax call ({})".format(dir_path))
|
||||
console.warning("Invalid path in create_dir ajax call ({})".format(dir_path))
|
||||
logger.warning(f"Invalid path in create_dir ajax call ({dir_path})")
|
||||
console.warning(f"Invalid path in create_dir ajax call ({dir_path})")
|
||||
return
|
||||
# Create the directory
|
||||
os.mkdir(dir_path)
|
||||
@ -265,7 +266,7 @@ class AjaxHandler(BaseHandler):
|
||||
server_id = self.get_argument('id', None)
|
||||
path = helper.get_os_understandable_path(self.get_argument('path', None))
|
||||
helper.unzipFile(path)
|
||||
self.redirect("/panel/server_detail?id={}&subpage=files".format(server_id))
|
||||
self.redirect(f"/panel/server_detail?id={server_id}&subpage=files")
|
||||
return
|
||||
|
||||
elif page == "kill":
|
||||
@ -278,7 +279,7 @@ class AjaxHandler(BaseHandler):
|
||||
try:
|
||||
svr.kill()
|
||||
except Exception as e:
|
||||
logger.error("Could not find PID for requested termsig. Full error: {}".format(e))
|
||||
logger.error(f"Could not find PID for requested termsig. Full error: {e}")
|
||||
return
|
||||
elif page == "eula":
|
||||
server_id = self.get_argument('id', None)
|
||||
@ -297,7 +298,11 @@ class AjaxHandler(BaseHandler):
|
||||
backup_path = svr_obj.backup_path
|
||||
if helper.validate_traversal(backup_path, zip_name):
|
||||
tempDir = helper.unzip_backup_archive(backup_path, zip_name)
|
||||
new_server = self.controller.import_zip_server(svr_obj.server_name, tempDir, server_data['executable'], '1', '2', server_data['server_port'])
|
||||
new_server = self.controller.import_zip_server(svr_obj.server_name,
|
||||
tempDir,
|
||||
server_data['executable'],
|
||||
'1', '2',
|
||||
server_data['server_port'])
|
||||
new_server_id = new_server
|
||||
new_server = self.controller.get_server_data(new_server)
|
||||
self.controller.rename_backup_dir(server_id, new_server_id, new_server['server_uuid'])
|
||||
@ -340,7 +345,7 @@ class AjaxHandler(BaseHandler):
|
||||
file_path = helper.get_os_understandable_path(self.get_body_argument('file_path', default=None, strip=True))
|
||||
server_id = self.get_argument('id', None)
|
||||
|
||||
console.warning("delete {} for server {}".format(file_path, server_id))
|
||||
console.warning(f"Delete {file_path} for server {server_id}")
|
||||
|
||||
if not self.check_server_id(server_id, 'del_file'):
|
||||
return
|
||||
@ -350,8 +355,8 @@ class AjaxHandler(BaseHandler):
|
||||
if not (helper.in_path(helper.get_os_understandable_path(server_info['path']), file_path) \
|
||||
or helper.in_path(helper.get_os_understandable_path(server_info['backup_path']), file_path)) \
|
||||
or not helper.check_file_exists(os.path.abspath(file_path)):
|
||||
logger.warning("Invalid path in del_file ajax call ({})".format(file_path))
|
||||
console.warning("Invalid path in del_file ajax call ({})".format(file_path))
|
||||
logger.warning(f"Invalid path in del_file ajax call ({file_path})")
|
||||
console.warning(f"Invalid path in del_file ajax call ({file_path})")
|
||||
return
|
||||
|
||||
# Delete the file
|
||||
@ -372,7 +377,7 @@ class AjaxHandler(BaseHandler):
|
||||
file_path = helper.get_os_understandable_path(self.get_body_argument('file_path', default=None, strip=True))
|
||||
server_id = self.get_argument('id', None)
|
||||
|
||||
console.warning("delete {} for server {}".format(file_path, server_id))
|
||||
console.warning(f"Delete {file_path} for server {server_id}")
|
||||
|
||||
if not self.check_server_id(server_id, 'del_file'):
|
||||
return
|
||||
@ -382,8 +387,8 @@ class AjaxHandler(BaseHandler):
|
||||
if not (helper.in_path(helper.get_os_understandable_path(server_info['path']), file_path) \
|
||||
or helper.in_path(helper.get_os_understandable_path(server_info['backup_path']), file_path)) \
|
||||
or not helper.check_file_exists(os.path.abspath(file_path)):
|
||||
logger.warning("Invalid path in del_file ajax call ({})".format(file_path))
|
||||
console.warning("Invalid path in del_file ajax call ({})".format(file_path))
|
||||
logger.warning(f"Invalid path in del_file ajax call ({file_path})")
|
||||
console.warning(f"Invalid path in del_file ajax call ({file_path})")
|
||||
return
|
||||
|
||||
# Delete the file
|
||||
@ -398,16 +403,18 @@ class AjaxHandler(BaseHandler):
|
||||
dir_path = helper.get_os_understandable_path(self.get_body_argument('dir_path', default=None, strip=True))
|
||||
server_id = self.get_argument('id', None)
|
||||
|
||||
console.warning("delete {} for server {}".format(dir_path, server_id))
|
||||
console.warning(f"Delete {dir_path} for server {server_id}")
|
||||
|
||||
if not self.check_server_id(server_id, 'del_dir'): return
|
||||
else: server_id = bleach.clean(server_id)
|
||||
if not self.check_server_id(server_id, 'del_dir'):
|
||||
return
|
||||
else:
|
||||
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)):
|
||||
logger.warning("Invalid path in del_file ajax call ({})".format(dir_path))
|
||||
console.warning("Invalid path in del_file ajax call ({})".format(dir_path))
|
||||
logger.warning(f"Invalid path in del_file ajax call ({dir_path})")
|
||||
console.warning(f"Invalid path in del_file ajax call ({dir_path})")
|
||||
return
|
||||
|
||||
# Delete the directory
|
||||
@ -421,14 +428,13 @@ class AjaxHandler(BaseHandler):
|
||||
self.redirect("/panel/error?error=Unauthorized access to Config")
|
||||
return
|
||||
server_id = self.get_argument('id', None)
|
||||
logger.info(
|
||||
"Removing server from panel for server: {}".format(self.controller.servers.get_server_friendly_name(server_id)))
|
||||
logger.info(f"Removing server from panel for server: {self.controller.servers.get_server_friendly_name(server_id)}")
|
||||
|
||||
server_data = self.controller.get_server_data(server_id)
|
||||
server_name = server_data['server_name']
|
||||
|
||||
self.controller.management.add_to_audit_log(exec_user['user_id'],
|
||||
"Deleted server {} named {}".format(server_id, server_name),
|
||||
f"Deleted server {server_id} named {server_name}",
|
||||
server_id,
|
||||
self.get_remote_ip())
|
||||
|
||||
@ -441,14 +447,13 @@ class AjaxHandler(BaseHandler):
|
||||
self.redirect("/panel/error?error=Unauthorized access to Config")
|
||||
return
|
||||
server_id = self.get_argument('id', None)
|
||||
logger.info(
|
||||
"Removing server and all associated files for server: {}".format(self.controller.servers.get_server_friendly_name(server_id)))
|
||||
logger.info(f"Removing server and all associated files for server: {self.controller.servers.get_server_friendly_name(server_id)}")
|
||||
|
||||
server_data = self.controller.get_server_data(server_id)
|
||||
server_name = server_data['server_name']
|
||||
|
||||
self.controller.management.add_to_audit_log(exec_user['user_id'],
|
||||
"Deleted server {} named {}".format(server_id, server_name),
|
||||
f"Deleted server {server_id} named {server_name}",
|
||||
server_id,
|
||||
self.get_remote_ip())
|
||||
|
||||
@ -483,17 +488,19 @@ class AjaxHandler(BaseHandler):
|
||||
file_path = helper.get_os_understandable_path(self.get_body_argument('file_path', default=None, strip=True))
|
||||
server_id = self.get_argument('id', None)
|
||||
|
||||
if not self.check_server_id(server_id, 'save_file'): return
|
||||
else: server_id = bleach.clean(server_id)
|
||||
if not self.check_server_id(server_id, 'save_file'):
|
||||
return
|
||||
else:
|
||||
server_id = bleach.clean(server_id)
|
||||
|
||||
if not helper.in_path(helper.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)):
|
||||
logger.warning("Invalid path in save_file ajax call ({})".format(file_path))
|
||||
console.warning("Invalid path in save_file ajax call ({})".format(file_path))
|
||||
logger.warning(f"Invalid path in save_file ajax call ({file_path})")
|
||||
console.warning(f"Invalid path in save_file ajax call ({file_path})")
|
||||
return
|
||||
|
||||
# Open the file in write mode and store the content in file_object
|
||||
with open(file_path, 'w') as file_object:
|
||||
with open(file_path, 'w', encoding='utf-8') as file_object:
|
||||
file_object.write(file_contents)
|
||||
|
||||
elif page == "rename_item":
|
||||
@ -505,8 +512,10 @@ class AjaxHandler(BaseHandler):
|
||||
new_item_name = self.get_body_argument('new_item_name', default=None, strip=True)
|
||||
server_id = self.get_argument('id', None)
|
||||
|
||||
if not self.check_server_id(server_id, 'rename_item'): return
|
||||
else: server_id = bleach.clean(server_id)
|
||||
if not self.check_server_id(server_id, 'rename_item'):
|
||||
return
|
||||
else:
|
||||
server_id = bleach.clean(server_id)
|
||||
|
||||
if item_path is None or new_item_name is None:
|
||||
logger.warning("Invalid path(s) in rename_item ajax call")
|
||||
@ -515,16 +524,17 @@ class AjaxHandler(BaseHandler):
|
||||
|
||||
if not helper.in_path(helper.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)):
|
||||
logger.warning("Invalid old name path in rename_item ajax call ({})".format(server_id))
|
||||
console.warning("Invalid old name path in rename_item ajax call ({})".format(server_id))
|
||||
logger.warning(f"Invalid old name path in rename_item ajax call ({server_id})")
|
||||
console.warning(f"Invalid old name path in rename_item 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(self.controller.servers.get_server_data_by_id(server_id)['path']), new_item_path) \
|
||||
if not helper.in_path(helper.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)):
|
||||
logger.warning("Invalid new name path in rename_item ajax call ({})".format(server_id))
|
||||
console.warning("Invalid new name path in rename_item ajax call ({})".format(server_id))
|
||||
logger.warning(f"Invalid new name path in rename_item ajax call ({server_id})")
|
||||
console.warning(f"Invalid new name path in rename_item ajax call ({server_id})")
|
||||
return
|
||||
|
||||
# RENAME
|
||||
@ -532,15 +542,15 @@ class AjaxHandler(BaseHandler):
|
||||
|
||||
def check_server_id(self, server_id, page_name):
|
||||
if server_id is None:
|
||||
logger.warning("Server ID not defined in {} ajax call ({})".format(page_name, server_id))
|
||||
console.warning("Server ID not defined in {} ajax call ({})".format(page_name, server_id))
|
||||
logger.warning(f"Server ID not defined in {page_name} ajax call ({server_id})")
|
||||
console.warning(f"Server ID not defined in {page_name} ajax call ({server_id})")
|
||||
return
|
||||
else:
|
||||
server_id = bleach.clean(server_id)
|
||||
|
||||
# does this server id exist?
|
||||
if not self.controller.servers.server_id_exists(server_id):
|
||||
logger.warning("Server ID not found in {} ajax call ({})".format(page_name, server_id))
|
||||
console.warning("Server ID not found in {} ajax call ({})".format(page_name, server_id))
|
||||
logger.warning(f"Server ID not found in {page_name} ajax call ({server_id})")
|
||||
console.warning(f"Server ID not found in {page_name} ajax call ({server_id})")
|
||||
return
|
||||
return True
|
||||
|
@ -15,7 +15,8 @@ class ApiHandler(BaseHandler):
|
||||
self.write(data)
|
||||
|
||||
def access_denied(self, user, reason=''):
|
||||
if reason: reason = ' because ' + reason
|
||||
if reason:
|
||||
reason = ' because ' + reason
|
||||
log.info("User %s from IP %s was denied access to the API route " + self.request.path + reason, user, self.get_remote_ip())
|
||||
self.finish(self.return_response(403, {
|
||||
'error':'ACCESS_DENIED',
|
||||
@ -36,7 +37,7 @@ class ApiHandler(BaseHandler):
|
||||
log.debug("Checking results")
|
||||
if user_data:
|
||||
# Login successful! Check perms
|
||||
log.info("User {} has authenticated to API".format(user_data['username']))
|
||||
log.info(f"User {user_data['username']} has authenticated to API")
|
||||
# TODO: Role check
|
||||
|
||||
return True # This is to set the "authenticated"
|
||||
@ -46,7 +47,10 @@ class ApiHandler(BaseHandler):
|
||||
return False
|
||||
except Exception as e:
|
||||
log.warning("An error occured while authenticating an API user: %s", e)
|
||||
self.access_denied("unknown"), "an error occured while authenticating the user"
|
||||
self.finish(self.return_response(403, {
|
||||
'error':'ACCESS_DENIED',
|
||||
'info':'An error occured while authenticating the user'
|
||||
}))
|
||||
return False
|
||||
|
||||
|
||||
@ -54,7 +58,9 @@ class ServersStats(ApiHandler):
|
||||
def get(self):
|
||||
"""Get details about all servers"""
|
||||
authenticated = self.authenticate_user()
|
||||
if not authenticated: return
|
||||
if not authenticated:
|
||||
return
|
||||
|
||||
# Get server stats
|
||||
# TODO Check perms
|
||||
self.finish(self.write({"servers": self.controller.stats.get_servers_stats()}))
|
||||
@ -64,7 +70,9 @@ class NodeStats(ApiHandler):
|
||||
def get(self):
|
||||
"""Get stats for particular node"""
|
||||
authenticated = self.authenticate_user()
|
||||
if not authenticated: return
|
||||
if not authenticated:
|
||||
return
|
||||
|
||||
# Get node stats
|
||||
node_stats = self.controller.stats.get_node_stats()
|
||||
node_stats.pop("servers")
|
||||
|
@ -1,14 +1,15 @@
|
||||
import logging
|
||||
import tornado.web
|
||||
import bleach
|
||||
from typing import (
|
||||
Union,
|
||||
List,
|
||||
Optional, Tuple, Dict, Any
|
||||
)
|
||||
import tornado.web
|
||||
import bleach
|
||||
|
||||
from app.classes.shared.authentication import authentication
|
||||
from app.classes.shared.main_controller import Controller
|
||||
|
||||
from app.classes.models.users import ApiKeys
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@ -38,10 +39,10 @@ class BaseHandler(tornado.web.RequestHandler):
|
||||
def autobleach(self, name, text):
|
||||
for r in self.redactables:
|
||||
if r in name:
|
||||
logger.debug("Auto-bleaching {}: {}".format(name, "[**REDACTED**]"))
|
||||
logger.debug(f"Auto-bleaching {name}: [**REDACTED**]")
|
||||
break
|
||||
else:
|
||||
logger.debug("Auto-bleaching {}: {}".format(name, text))
|
||||
logger.debug(f"Auto-bleaching {name}: {text}")
|
||||
if type(text) in self.nobleach:
|
||||
logger.debug("Auto-bleaching - bypass type")
|
||||
return text
|
||||
|
@ -4,10 +4,10 @@ from app.classes.web.base_handler import BaseHandler
|
||||
|
||||
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):
|
||||
if page is not None:
|
||||
self.set_status(404)
|
||||
@ -20,4 +20,3 @@ class DefaultHandler(BaseHandler):
|
||||
"/public/login",
|
||||
#translate=self.translator.translate,
|
||||
)
|
||||
|
||||
|
@ -1,26 +1,11 @@
|
||||
import sys
|
||||
import json
|
||||
import logging
|
||||
import tornado.web
|
||||
import tornado.escape
|
||||
import requests
|
||||
|
||||
from app.classes.shared.helpers import helper
|
||||
from app.classes.web.base_handler import BaseHandler
|
||||
from app.classes.shared.console import console
|
||||
from app.classes.shared.main_models import Users, fn
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
try:
|
||||
import bleach
|
||||
|
||||
except ModuleNotFoundError as e:
|
||||
logger.critical("Import Error: Unable to load {} module".format(e.name), exc_info=True)
|
||||
console.critical("Import Error: Unable to load {} module".format(e.name))
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
class HTTPHandler(BaseHandler):
|
||||
def get(self):
|
||||
url = str(self.request.host)
|
||||
@ -34,13 +19,13 @@ class HTTPHandler(BaseHandler):
|
||||
try:
|
||||
resp = requests.get(url + ":" + str(port))
|
||||
resp.raise_for_status()
|
||||
except Exception as err:
|
||||
except Exception:
|
||||
port = db_port
|
||||
self.redirect(url+":"+str(port))
|
||||
|
||||
|
||||
class HTTPHandlerPage(BaseHandler):
|
||||
def get(self, page):
|
||||
def get(self):
|
||||
url = str(self.request.host)
|
||||
port = 443
|
||||
url_list = url.split(":")
|
||||
@ -52,6 +37,6 @@ class HTTPHandlerPage(BaseHandler):
|
||||
try:
|
||||
resp = requests.get(url + ":" + str(port))
|
||||
resp.raise_for_status()
|
||||
except Exception as err:
|
||||
except Exception:
|
||||
port = db_port
|
||||
self.redirect(url+":"+str(port))
|
@ -1,28 +1,12 @@
|
||||
import sys
|
||||
import json
|
||||
import logging
|
||||
import tornado.web
|
||||
import tornado.escape
|
||||
import requests
|
||||
|
||||
from app.classes.shared.helpers import helper
|
||||
from app.classes.web.base_handler import BaseHandler
|
||||
from app.classes.shared.console import console
|
||||
from app.classes.shared.main_models import Users, fn
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
try:
|
||||
import bleach
|
||||
|
||||
except ModuleNotFoundError as e:
|
||||
logger.critical("Import Error: Unable to load {} module".format(e.name), exc_info=True)
|
||||
console.critical("Import Error: Unable to load {} module".format(e.name))
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
class HTTPHandlerPage(BaseHandler):
|
||||
def get(self, page):
|
||||
def get(self):
|
||||
url = self.request.full_url
|
||||
port = 443
|
||||
if url[len(url)-1] == '/':
|
||||
@ -30,18 +14,18 @@ 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(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(helper.get_setting('https_port'))
|
||||
|
||||
try:
|
||||
resp = requests.get(primary_url)
|
||||
resp.raise_for_status()
|
||||
url = primary_url
|
||||
except Exception as err:
|
||||
except Exception:
|
||||
url = backup_url
|
||||
self.redirect('https://'+url+':'+ str(port))
|
@ -1,43 +1,34 @@
|
||||
from tempfile import tempdir
|
||||
from typing import Dict, Optional, Any
|
||||
|
||||
from app.classes.shared.authentication import authentication
|
||||
from app.classes.shared.translation import Translation
|
||||
import json
|
||||
import logging
|
||||
import tornado.web
|
||||
import tornado.escape
|
||||
import bleach
|
||||
import time
|
||||
import datetime
|
||||
import os
|
||||
import shutil
|
||||
import tempfile
|
||||
from typing import Dict, Any, Tuple
|
||||
import json
|
||||
import logging
|
||||
import threading
|
||||
from cron_validator import CronValidator
|
||||
#TZLocal is set as a hidden import on win pipeline
|
||||
from tzlocal import get_localzone
|
||||
import bleach
|
||||
import libgravatar
|
||||
import requests
|
||||
|
||||
from tornado import locale, iostream
|
||||
import tornado.web
|
||||
import tornado.escape
|
||||
from tornado import iostream
|
||||
from tornado.ioloop import IOLoop
|
||||
from app.classes.shared.console import console
|
||||
from app.classes.shared.main_models import Users, installer
|
||||
|
||||
#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 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
|
||||
|
||||
from app.classes.web.base_handler import BaseHandler
|
||||
|
||||
from app.classes.models.servers import Servers
|
||||
from app.classes.models.server_permissions import Enum_Permissions_Server, Permissions_Servers
|
||||
from app.classes.models.crafty_permissions import Enum_Permissions_Crafty, Permissions_Crafty
|
||||
from app.classes.models.management import management_helper
|
||||
|
||||
from app.classes.shared.helpers import helper
|
||||
from app.classes.web.websocket_helper import WebSocketHelper
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class PanelHandler(BaseHandler):
|
||||
|
||||
def get_user_roles(self) -> Dict[str, list]:
|
||||
@ -53,26 +44,26 @@ class PanelHandler(BaseHandler):
|
||||
for server in self.controller.list_defined_servers():
|
||||
argument = int(float(
|
||||
bleach.clean(
|
||||
self.get_argument('server_{}_access'.format(server['server_id']), '0')
|
||||
self.get_argument(f"server_{server['server_id']}_access", '0')
|
||||
)
|
||||
))
|
||||
if argument:
|
||||
servers.add(server['server_id'])
|
||||
return servers
|
||||
|
||||
def get_perms_quantity(self) -> (str, dict):
|
||||
def get_perms_quantity(self) -> Tuple[str, dict]:
|
||||
permissions_mask: str = "000"
|
||||
server_quantity: dict = {}
|
||||
for permission in self.controller.crafty_perms.list_defined_crafty_permissions():
|
||||
argument = int(float(bleach.clean(
|
||||
self.get_argument('permission_{}'.format(permission.name), '0')
|
||||
self.get_argument(f'permission_{permission.name}', '0')
|
||||
)))
|
||||
if argument:
|
||||
permissions_mask = self.controller.crafty_perms.set_permission(permissions_mask, permission, argument)
|
||||
|
||||
q_argument = int(float(
|
||||
bleach.clean(
|
||||
self.get_argument('quantity_{}'.format(permission.name), '0')
|
||||
self.get_argument(f'quantity_{permission.name}', '0')
|
||||
)
|
||||
))
|
||||
if q_argument:
|
||||
@ -84,7 +75,7 @@ class PanelHandler(BaseHandler):
|
||||
def get_perms(self) -> str:
|
||||
permissions_mask: str = "000"
|
||||
for permission in self.controller.crafty_perms.list_defined_crafty_permissions():
|
||||
argument = self.get_argument('permission_{}'.format(permission.name), None)
|
||||
argument = self.get_argument(f'permission_{permission.name}', None)
|
||||
if argument is not None:
|
||||
permissions_mask = self.controller.crafty_perms.set_permission(permissions_mask, permission,
|
||||
1 if argument == '1' else 0)
|
||||
@ -93,7 +84,7 @@ class PanelHandler(BaseHandler):
|
||||
def get_perms_server(self) -> str:
|
||||
permissions_mask = "00000000"
|
||||
for permission in self.controller.server_perms.list_defined_permissions():
|
||||
argument = self.get_argument('permission_{}'.format(permission.name), None)
|
||||
argument = self.get_argument(f'permission_{permission.name}', None)
|
||||
if argument is not None:
|
||||
permissions_mask = self.controller.server_perms.set_permission(permissions_mask, permission,
|
||||
1 if argument == '1' else 0)
|
||||
@ -102,13 +93,13 @@ class PanelHandler(BaseHandler):
|
||||
def get_user_role_memberships(self) -> set:
|
||||
roles = set()
|
||||
for role in self.controller.roles.get_all_roles():
|
||||
if self.get_argument('role_{}_membership'.format(role.role_id), None) == '1':
|
||||
if self.get_argument(f'role_{role.role_id}_membership', None) == '1':
|
||||
roles.add(role.role_id)
|
||||
return roles
|
||||
|
||||
def download_file(self, name: str, file: str):
|
||||
self.set_header('Content-Type', 'application/octet-stream')
|
||||
self.set_header('Content-Disposition', 'attachment; filename=' + name)
|
||||
self.set_header('Content-Disposition', f'attachment; filename={name}')
|
||||
chunk_size = 1024 * 1024 * 4 # 4 MiB
|
||||
|
||||
with open(file, 'rb') as f:
|
||||
@ -176,7 +167,7 @@ class PanelHandler(BaseHandler):
|
||||
data = json.loads(s['int_ping_results'])
|
||||
s['int_ping_results'] = data
|
||||
except Exception as e:
|
||||
logger.error("Failed server data for page with error: {} ".format(e))
|
||||
logger.error(f"Failed server data for page with error: {e}")
|
||||
|
||||
return page_data
|
||||
|
||||
@ -190,6 +181,7 @@ class PanelHandler(BaseHandler):
|
||||
now = time.time()
|
||||
formatted_time = str(datetime.datetime.fromtimestamp(now).strftime('%Y-%m-%d %H:%M:%S'))
|
||||
|
||||
# pylint: disable=unused-variable
|
||||
api_key, token_data, exec_user = self.current_user
|
||||
superuser = exec_user['superuser']
|
||||
if api_key is not None:
|
||||
@ -272,7 +264,7 @@ class PanelHandler(BaseHandler):
|
||||
template = "public/error.html"
|
||||
|
||||
elif page == 'credits':
|
||||
with open(helper.credits_cache) as republic_credits_will_do:
|
||||
with open(helper.credits_cache, encoding='utf-8') as republic_credits_will_do:
|
||||
credits_dict: dict = json.load(republic_credits_will_do)
|
||||
timestamp = credits_dict["lastUpdate"] / 1000.0
|
||||
page_data["patrons"] = credits_dict["patrons"]
|
||||
@ -308,7 +300,7 @@ class PanelHandler(BaseHandler):
|
||||
data['stats']['waiting_start'] = self.controller.servers.get_waiting_start(
|
||||
str(data['stats']['server_id']['server_id']))
|
||||
except Exception as e:
|
||||
logger.error("Failed to get server waiting to start: {} ".format(e))
|
||||
logger.error(f"Failed to get server waiting to start: {e}")
|
||||
data['stats']['waiting_start'] = False
|
||||
|
||||
try:
|
||||
@ -324,14 +316,15 @@ class PanelHandler(BaseHandler):
|
||||
subpage = bleach.clean(self.get_argument('subpage', ""))
|
||||
|
||||
server_id = self.check_server_id()
|
||||
if server_id is None: return
|
||||
if server_id is None:
|
||||
return
|
||||
|
||||
valid_subpages = ['term', 'logs', 'backup', 'config', 'files', 'admin_controls', 'tasks']
|
||||
|
||||
if subpage not in valid_subpages:
|
||||
logger.debug('not a valid subpage')
|
||||
subpage = 'term'
|
||||
logger.debug('Subpage: "{}"'.format(subpage))
|
||||
logger.debug(f'Subpage: "{subpage}"')
|
||||
|
||||
server = self.controller.get_server_obj(server_id)
|
||||
# server_data isn't needed since the server_stats also pulls server data
|
||||
@ -340,7 +333,7 @@ class PanelHandler(BaseHandler):
|
||||
try:
|
||||
page_data['waiting_start'] = self.controller.servers.get_waiting_start(server_id)
|
||||
except Exception as e:
|
||||
logger.error("Failed to get server waiting to start: {} ".format(e))
|
||||
logger.error(f"Failed to get server waiting to start: {e}")
|
||||
page_data['waiting_start'] = False
|
||||
page_data['get_players'] = lambda: self.controller.stats.get_server_players(server_id)
|
||||
page_data['active_link'] = subpage
|
||||
@ -413,13 +406,13 @@ class PanelHandler(BaseHandler):
|
||||
"""
|
||||
html = ""
|
||||
for player in banned_players:
|
||||
html += """
|
||||
html += f"""
|
||||
<li class="playerItem banned">
|
||||
<h3>{}</h3>
|
||||
<span>Banned by {} for reason: {}</span>
|
||||
<button onclick="send_command_to_server('pardon {}')" type="button" class="btn btn-danger">Unban</button>
|
||||
<h3>{player['name']}</h3>
|
||||
<span>Banned by {player['source']} for reason: {player['reason']}</span>
|
||||
<button onclick="send_command_to_server('pardon {player['name']}')" type="button" class="btn btn-danger">Unban</button>
|
||||
</li>
|
||||
""".format(player['name'], player['source'], player['reason'], player['name'])
|
||||
"""
|
||||
|
||||
return html
|
||||
if subpage == "admin_controls":
|
||||
@ -428,14 +421,14 @@ class PanelHandler(BaseHandler):
|
||||
self.redirect("/panel/error?error=Unauthorized access")
|
||||
page_data['banned_players'] = get_banned_players_html()
|
||||
|
||||
# template = "panel/server_details.html"
|
||||
template = "panel/server_{subpage}.html".format(subpage=subpage)
|
||||
template = f"panel/server_{subpage}.html"
|
||||
|
||||
elif page == 'download_backup':
|
||||
file = self.get_argument('file', "")
|
||||
|
||||
server_id = self.check_server_id()
|
||||
if server_id is None: return
|
||||
if server_id is None:
|
||||
return
|
||||
|
||||
|
||||
server_info = self.controller.servers.get_server_data_by_id(server_id)
|
||||
@ -447,16 +440,17 @@ class PanelHandler(BaseHandler):
|
||||
|
||||
self.download_file(file, backup_file)
|
||||
|
||||
self.redirect("/panel/server_detail?id={}&subpage=backup".format(server_id))
|
||||
self.redirect(f"/panel/server_detail?id={server_id}&subpage=backup")
|
||||
|
||||
elif page == 'backup_now':
|
||||
server_id = self.check_server_id()
|
||||
if server_id is None: return
|
||||
if server_id is None:
|
||||
return
|
||||
|
||||
server = self.controller.get_server_obj(server_id)
|
||||
|
||||
server.backup_server()
|
||||
self.redirect("/panel/server_detail?id={}&subpage=backup".format(server_id))
|
||||
self.redirect(f"/panel/server_detail?id={server_id}&subpage=backup")
|
||||
|
||||
elif page == 'panel_config':
|
||||
auth_servers = {}
|
||||
@ -607,7 +601,8 @@ class PanelHandler(BaseHandler):
|
||||
page_data['schedule']['server_id'] = server_id
|
||||
page_data['schedule']['schedule_id'] = schedule.schedule_id
|
||||
page_data['schedule']['action'] = schedule.action
|
||||
#we check here to see if the command is any of the default ones. We do not want a user changing to a custom command and seeing our command there.
|
||||
# We check here to see if the command is any of the default ones.
|
||||
# We do not want a user changing to a custom command and seeing our command there.
|
||||
if schedule.action != 'start' or schedule.action != 'stop' or schedule.action != 'restart' or schedule.action != 'backup':
|
||||
page_data['schedule']['command'] = schedule.command
|
||||
else:
|
||||
@ -624,7 +619,7 @@ class PanelHandler(BaseHandler):
|
||||
difficulty = 'advanced'
|
||||
page_data['schedule']['difficulty'] = difficulty
|
||||
|
||||
if sch_id == None or server_id == None:
|
||||
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']:
|
||||
@ -803,7 +798,8 @@ class PanelHandler(BaseHandler):
|
||||
name = self.get_argument('name', "")
|
||||
|
||||
server_id = self.check_server_id()
|
||||
if server_id is None: return
|
||||
if server_id is None:
|
||||
return
|
||||
|
||||
server_info = self.controller.servers.get_server_data_by_id(server_id)
|
||||
|
||||
@ -813,7 +809,7 @@ class PanelHandler(BaseHandler):
|
||||
return
|
||||
|
||||
self.download_file(name, file)
|
||||
self.redirect("/panel/server_detail?id={}&subpage=files".format(server_id))
|
||||
self.redirect(f"/panel/server_detail?id={server_id}&subpage=files")
|
||||
|
||||
elif page == 'download_support_package':
|
||||
tempZipStorage = exec_user['support_logs']
|
||||
@ -848,8 +844,11 @@ class PanelHandler(BaseHandler):
|
||||
return
|
||||
|
||||
elif page == "support_logs":
|
||||
logger.info("Support logs requested. Packinging logs for user with ID: {}".format(exec_user["user_id"]))
|
||||
logs_thread = threading.Thread(target=self.controller.package_support_logs, daemon=True, args=(exec_user,), name='{}_logs_thread'.format(exec_user['user_id']))
|
||||
logger.info(f"Support logs requested. Packinging logs for user with ID: {exec_user['user_id']}")
|
||||
logs_thread = threading.Thread(target=self.controller.package_support_logs,
|
||||
daemon=True,
|
||||
args=(exec_user,),
|
||||
name=f"{exec_user['user_id']}_logs_thread")
|
||||
logs_thread.start()
|
||||
self.redirect('/panel/dashboard')
|
||||
return
|
||||
@ -866,6 +865,7 @@ class PanelHandler(BaseHandler):
|
||||
|
||||
@tornado.web.authenticated
|
||||
def post(self, page):
|
||||
# pylint: disable=unused-variable
|
||||
api_key, token_data, exec_user = self.current_user
|
||||
superuser = exec_user['superuser']
|
||||
if api_key is not None:
|
||||
@ -923,14 +923,13 @@ class PanelHandler(BaseHandler):
|
||||
auto_start = int(float(self.get_argument('auto_start', '0')))
|
||||
crash_detection = int(float(self.get_argument('crash_detection', '0')))
|
||||
logs_delete_after = int(float(self.get_argument('logs_delete_after', '0')))
|
||||
# TODO: Add more modify options via the subpage parameter
|
||||
# subpage = self.get_argument('subpage', None)
|
||||
|
||||
server_id = self.check_server_id()
|
||||
if server_id is None: return
|
||||
if server_id is None:
|
||||
return
|
||||
|
||||
server_obj = self.controller.servers.get_server_obj(server_id)
|
||||
server_settings = self.controller.get_server_data(server_id)
|
||||
stale_executable = server_obj.executable
|
||||
#Compares old jar name to page data being passed. If they are different we replace the executable name in the
|
||||
if str(stale_executable) != str(executable):
|
||||
@ -966,11 +965,11 @@ class PanelHandler(BaseHandler):
|
||||
self.controller.refresh_server_settings(server_id)
|
||||
|
||||
self.controller.management.add_to_audit_log(exec_user['user_id'],
|
||||
"Edited server {} named {}".format(server_id, server_name),
|
||||
f"Edited server {server_id} named {server_name}",
|
||||
server_id,
|
||||
self.get_remote_ip())
|
||||
|
||||
self.redirect("/panel/server_detail?id={}&subpage=config".format(server_id))
|
||||
self.redirect(f"/panel/server_detail?id={server_id}&subpage=config")
|
||||
|
||||
if page == "server_backup":
|
||||
logger.debug(self.request.arguments)
|
||||
@ -1008,7 +1007,7 @@ class PanelHandler(BaseHandler):
|
||||
server_id,
|
||||
self.get_remote_ip())
|
||||
self.tasks_manager.reload_schedule_from_db()
|
||||
self.redirect("/panel/server_detail?id={}&subpage=backup".format(server_id))
|
||||
self.redirect(f"/panel/server_detail?id={server_id}&subpage=backup")
|
||||
|
||||
|
||||
if page == "new_schedule":
|
||||
@ -1022,7 +1021,7 @@ class PanelHandler(BaseHandler):
|
||||
interval_type = bleach.clean(self.get_argument('interval_type', None))
|
||||
#only check for time if it's number of days
|
||||
if interval_type == "days":
|
||||
time = bleach.clean(self.get_argument('time', None))
|
||||
sch_time = bleach.clean(self.get_argument('time', None))
|
||||
if action == "command":
|
||||
command = bleach.clean(self.get_argument('command', None))
|
||||
elif action == "start":
|
||||
@ -1039,7 +1038,7 @@ class PanelHandler(BaseHandler):
|
||||
try:
|
||||
CronValidator.parse(cron_string)
|
||||
except Exception as e:
|
||||
self.redirect("/panel/error?error=INVALID FORMAT: Invalid Cron Format. {}".format(e))
|
||||
self.redirect(f"/panel/error?error=INVALID FORMAT: Invalid Cron Format. {e}")
|
||||
return
|
||||
action = bleach.clean(self.get_argument('action', None))
|
||||
if action == "command":
|
||||
@ -1061,7 +1060,8 @@ class PanelHandler(BaseHandler):
|
||||
else:
|
||||
one_time = False
|
||||
|
||||
if not superuser and not permissions['Backup'] in self.controller.server_perms.get_user_id_permissions_list(exec_user["user_id"], server_id):
|
||||
if not superuser and not permissions['Backup'] in self.controller.server_perms.get_user_id_permissions_list(exec_user["user_id"],
|
||||
server_id):
|
||||
self.redirect("/panel/error?error=Unauthorized access: User not authorized")
|
||||
return
|
||||
elif server_id is None:
|
||||
@ -1072,13 +1072,6 @@ class PanelHandler(BaseHandler):
|
||||
if not self.controller.servers.server_id_exists(server_id):
|
||||
self.redirect("/panel/error?error=Invalid Server ID")
|
||||
return
|
||||
minute = datetime.datetime.now().minute
|
||||
hour = datetime.datetime.now().hour
|
||||
if minute < 10:
|
||||
minute = '0' + str(minute)
|
||||
if hour < 10:
|
||||
hour = '0'+str(hour)
|
||||
current_time = str(hour)+':'+str(minute)
|
||||
|
||||
if interval_type == "days":
|
||||
job_data = {
|
||||
@ -1087,7 +1080,7 @@ class PanelHandler(BaseHandler):
|
||||
"interval_type": interval_type,
|
||||
"interval": interval,
|
||||
"command": command,
|
||||
"start_time": time,
|
||||
"start_time": sch_time,
|
||||
"enabled": enabled,
|
||||
"one_time": one_time,
|
||||
"cron_string": ''
|
||||
@ -1098,7 +1091,6 @@ class PanelHandler(BaseHandler):
|
||||
"action": action,
|
||||
"interval_type": '',
|
||||
"interval": '',
|
||||
"command": '',
|
||||
#We'll base every interval off of a midnight start time.
|
||||
"start_time": '',
|
||||
"command": command,
|
||||
@ -1123,11 +1115,11 @@ class PanelHandler(BaseHandler):
|
||||
self.tasks_manager.schedule_job(job_data)
|
||||
|
||||
self.controller.management.add_to_audit_log(exec_user['user_id'],
|
||||
"Edited server {}: added scheduled job".format(server_id),
|
||||
f"Edited server {server_id}: added scheduled job",
|
||||
server_id,
|
||||
self.get_remote_ip())
|
||||
self.tasks_manager.reload_schedule_from_db()
|
||||
self.redirect("/panel/server_detail?id={}&subpage=tasks".format(server_id))
|
||||
self.redirect(f"/panel/server_detail?id={server_id}&subpage=tasks")
|
||||
|
||||
|
||||
if page == "edit_schedule":
|
||||
@ -1141,7 +1133,7 @@ class PanelHandler(BaseHandler):
|
||||
interval_type = bleach.clean(self.get_argument('interval_type', None))
|
||||
#only check for time if it's number of days
|
||||
if interval_type == "days":
|
||||
time = bleach.clean(self.get_argument('time', None))
|
||||
sch_time = bleach.clean(self.get_argument('time', None))
|
||||
if action == "command":
|
||||
command = bleach.clean(self.get_argument('command', None))
|
||||
elif action == "start":
|
||||
@ -1159,7 +1151,7 @@ class PanelHandler(BaseHandler):
|
||||
try:
|
||||
CronValidator.parse(cron_string)
|
||||
except Exception as e:
|
||||
self.redirect("/panel/error?error=INVALID FORMAT: Invalid Cron Format. {}".format(e))
|
||||
self.redirect(f"/panel/error?error=INVALID FORMAT: Invalid Cron Format. {e}")
|
||||
return
|
||||
action = bleach.clean(self.get_argument('action', None))
|
||||
if action == "command":
|
||||
@ -1181,7 +1173,8 @@ class PanelHandler(BaseHandler):
|
||||
else:
|
||||
one_time = False
|
||||
|
||||
if not superuser and not permissions['Backup'] in self.controller.server_perms.get_user_id_permissions_list(exec_user["user_id"], server_id):
|
||||
if not superuser and not permissions['Backup'] in self.controller.server_perms.get_user_id_permissions_list(exec_user["user_id"],
|
||||
server_id):
|
||||
self.redirect("/panel/error?error=Unauthorized access: User not authorized")
|
||||
return
|
||||
elif server_id is None:
|
||||
@ -1192,13 +1185,6 @@ class PanelHandler(BaseHandler):
|
||||
if not self.controller.servers.server_id_exists(server_id):
|
||||
self.redirect("/panel/error?error=Invalid Server ID")
|
||||
return
|
||||
minute = datetime.datetime.now().minute
|
||||
hour = datetime.datetime.now().hour
|
||||
if minute < 10:
|
||||
minute = '0' + str(minute)
|
||||
if hour < 10:
|
||||
hour = '0'+str(hour)
|
||||
current_time = str(hour)+':'+str(minute)
|
||||
|
||||
if interval_type == "days":
|
||||
job_data = {
|
||||
@ -1207,7 +1193,7 @@ class PanelHandler(BaseHandler):
|
||||
"interval_type": interval_type,
|
||||
"interval": interval,
|
||||
"command": command,
|
||||
"start_time": time,
|
||||
"start_time": sch_time,
|
||||
"enabled": enabled,
|
||||
"one_time": one_time,
|
||||
"cron_string": ''
|
||||
@ -1218,7 +1204,6 @@ class PanelHandler(BaseHandler):
|
||||
"action": action,
|
||||
"interval_type": '',
|
||||
"interval": '',
|
||||
"command": '',
|
||||
#We'll base every interval off of a midnight start time.
|
||||
"start_time": '',
|
||||
"command": command,
|
||||
@ -1243,11 +1228,11 @@ class PanelHandler(BaseHandler):
|
||||
self.tasks_manager.update_job(sch_id, job_data)
|
||||
|
||||
self.controller.management.add_to_audit_log(exec_user['user_id'],
|
||||
"Edited server {}: updated schedule".format(server_id),
|
||||
f"Edited server {server_id}: updated schedule",
|
||||
server_id,
|
||||
self.get_remote_ip())
|
||||
self.tasks_manager.reload_schedule_from_db()
|
||||
self.redirect("/panel/server_detail?id={}&subpage=tasks".format(server_id))
|
||||
self.redirect(f"/panel/server_detail?id={server_id}&subpage=tasks")
|
||||
|
||||
|
||||
elif page == "edit_user":
|
||||
@ -1262,7 +1247,8 @@ class PanelHandler(BaseHandler):
|
||||
lang = bleach.clean(self.get_argument('language'), helper.get_setting('language'))
|
||||
|
||||
if superuser:
|
||||
#Checks if user is trying to change super user status of self. We don't want that. Automatically make them stay super user since we know they are.
|
||||
#Checks if user is trying to change super user status of self. We don't want that.
|
||||
# Automatically make them stay super user since we know they are.
|
||||
if str(exec_user['user_id']) != str(user_id):
|
||||
superuser = bleach.clean(self.get_argument('superuser', '0'))
|
||||
else:
|
||||
@ -1358,7 +1344,8 @@ class PanelHandler(BaseHandler):
|
||||
self.controller.users.add_user_api_key(name, user_id, superuser, crafty_permissions_mask, server_permissions_mask)
|
||||
|
||||
self.controller.management.add_to_audit_log(exec_user['user_id'],
|
||||
f"Added API key {name} with crafty permissions {crafty_permissions_mask} and {server_permissions_mask} for user with UID: {user_id}",
|
||||
f"Added API key {name} with crafty permissions {crafty_permissions_mask}" +
|
||||
f" and {server_permissions_mask} for user with UID: {user_id}",
|
||||
server_id=0,
|
||||
source_ip=self.get_remote_ip())
|
||||
self.redirect(f"/panel/edit_user_apikeys?id={user_id}")
|
||||
@ -1389,13 +1376,14 @@ class PanelHandler(BaseHandler):
|
||||
|
||||
elif page == "add_user":
|
||||
if bleach.clean(self.get_argument('username', None)).lower() == 'system':
|
||||
self.redirect("/panel/error?error=Unauthorized access: username system is reserved for the Crafty system. Please choose a different username.")
|
||||
self.redirect("/panel/error?error=Unauthorized access: username system is reserved for the Crafty system." +
|
||||
" Please choose a different username.")
|
||||
return
|
||||
username = bleach.clean(self.get_argument('username', None))
|
||||
password0 = bleach.clean(self.get_argument('password0', None))
|
||||
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'))),
|
||||
enabled = int(float(self.get_argument('enabled', '0')))
|
||||
lang = bleach.clean(self.get_argument('lang', helper.get_setting('language')))
|
||||
if superuser:
|
||||
superuser = bleach.clean(self.get_argument('superuser', '0'))
|
||||
@ -1437,11 +1425,11 @@ class PanelHandler(BaseHandler):
|
||||
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'],
|
||||
"Added user {} (UID:{})".format(username, user_id),
|
||||
f"Added user {username} (UID:{user_id})",
|
||||
server_id=0,
|
||||
source_ip=self.get_remote_ip())
|
||||
self.controller.management.add_to_audit_log(exec_user['user_id'],
|
||||
"Edited user {} (UID:{}) with roles {}".format(username, user_id, roles),
|
||||
f"Edited user {username} (UID:{user_id}) with roles {roles}",
|
||||
server_id=0,
|
||||
source_ip=self.get_remote_ip())
|
||||
self.redirect("/panel/panel_config")
|
||||
@ -1475,7 +1463,7 @@ class PanelHandler(BaseHandler):
|
||||
self.controller.roles.update_role(role_id, role_data=role_data, permissions_mask=permissions_mask)
|
||||
|
||||
self.controller.management.add_to_audit_log(exec_user['user_id'],
|
||||
"Edited role {} (RID:{}) with servers {}".format(role_name, role_id, servers),
|
||||
f"Edited role {role_name} (RID:{role_id}) with servers {servers}",
|
||||
server_id=0,
|
||||
source_ip=self.get_remote_ip())
|
||||
self.redirect("/panel/panel_config")
|
||||
@ -1503,11 +1491,11 @@ class PanelHandler(BaseHandler):
|
||||
self.controller.roles.update_role(role_id, {"servers": servers}, permissions_mask)
|
||||
|
||||
self.controller.management.add_to_audit_log(exec_user['user_id'],
|
||||
"Added role {} (RID:{})".format(role_name, role_id),
|
||||
f"Added role {role_name} (RID:{role_id})",
|
||||
server_id=0,
|
||||
source_ip=self.get_remote_ip())
|
||||
self.controller.management.add_to_audit_log(exec_user['user_id'],
|
||||
"Edited role {} (RID:{}) with servers {}".format(role_name, role_id, servers),
|
||||
f"Edited role {role_name} (RID:{role_id}) with servers {servers}",
|
||||
server_id=0,
|
||||
source_ip=self.get_remote_ip())
|
||||
self.redirect("/panel/panel_config")
|
||||
@ -1523,6 +1511,7 @@ class PanelHandler(BaseHandler):
|
||||
|
||||
@tornado.web.authenticated
|
||||
def delete(self, page):
|
||||
# pylint: disable=unused-variable
|
||||
api_key, token_data, exec_user = self.current_user
|
||||
superuser = exec_user['superuser']
|
||||
if api_key is not None:
|
||||
|
@ -1,19 +1,13 @@
|
||||
from re import X
|
||||
import sys
|
||||
import json
|
||||
import libgravatar
|
||||
import logging
|
||||
import requests
|
||||
import tornado.web
|
||||
import tornado.escape
|
||||
|
||||
from app.classes.shared.authentication import authentication
|
||||
from app.classes.shared.helpers import Helpers, helper
|
||||
from app.classes.web.base_handler import BaseHandler
|
||||
from app.classes.shared.helpers import helper
|
||||
from app.classes.shared.console import console
|
||||
from app.classes.shared.main_models import fn
|
||||
|
||||
from app.classes.models.users import Users
|
||||
from app.classes.web.base_handler import BaseHandler
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@ -21,11 +15,10 @@ try:
|
||||
import bleach
|
||||
|
||||
except ModuleNotFoundError as e:
|
||||
logger.critical("Import Error: Unable to load {} module".format(e.name), exc_info=True)
|
||||
console.critical("Import Error: Unable to load {} module".format(e.name))
|
||||
logger.critical(f"Import Error: Unable to load {e.name} module", exc_info=True)
|
||||
console.critical(f"Import Error: Unable to load {e.name} module")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
class PublicHandler(BaseHandler):
|
||||
|
||||
def set_current_user(self, user_id: str = None):
|
||||
@ -86,14 +79,16 @@ class PublicHandler(BaseHandler):
|
||||
entered_username = bleach.clean(self.get_argument('username'))
|
||||
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())
|
||||
|
||||
|
||||
# if we don't have a user
|
||||
if not user_data:
|
||||
error_msg = "Inncorrect username or password. Please try again."
|
||||
error_msg = "Incorrect username or password. Please try again."
|
||||
self.clear_cookie("user")
|
||||
self.clear_cookie("user_data")
|
||||
self.redirect('/public/login?error_msg={}'.format(error_msg))
|
||||
self.redirect(f'/public/login?error_msg={error_msg}')
|
||||
return
|
||||
|
||||
# if they are disabled
|
||||
@ -101,7 +96,7 @@ class PublicHandler(BaseHandler):
|
||||
error_msg = "User account disabled. Please contact your system administrator for more info."
|
||||
self.clear_cookie("user")
|
||||
self.clear_cookie("user_data")
|
||||
self.redirect('/public/login?error_msg={}'.format(error_msg))
|
||||
self.redirect(f'/public/login?error_msg={error_msg}')
|
||||
return
|
||||
|
||||
login_result = helper.verify_pass(entered_password, user_data.password)
|
||||
@ -109,7 +104,7 @@ class PublicHandler(BaseHandler):
|
||||
# Valid Login
|
||||
if login_result:
|
||||
self.set_current_user(user_data.user_id)
|
||||
logger.info("User: {} Logged in from IP: {}".format(user_data, self.get_remote_ip()))
|
||||
logger.info(f"User: {user_data} Logged in from IP: {self.get_remote_ip()}")
|
||||
|
||||
# record this login
|
||||
q = Users.select().where(Users.username == entered_username.lower()).get()
|
||||
@ -128,7 +123,6 @@ class PublicHandler(BaseHandler):
|
||||
error_msg = "Inncorrect username or password. Please try again."
|
||||
# log this failed login attempt
|
||||
self.controller.management.add_to_audit_log(user_data.user_id, "Tried to log in", 0, self.get_remote_ip())
|
||||
self.redirect('/public/login?error_msg={}'.format(error_msg))
|
||||
self.redirect(f'/public/login?error_msg={error_msg}')
|
||||
else:
|
||||
self.redirect("/public/login")
|
||||
|
||||
|
@ -3,14 +3,14 @@ import json
|
||||
import logging
|
||||
import os
|
||||
import shutil
|
||||
import libgravatar
|
||||
import requests
|
||||
|
||||
from app.classes.shared.helpers import helper
|
||||
from app.classes.shared.console import console
|
||||
from app.classes.web.base_handler import BaseHandler
|
||||
from app.classes.models.crafty_permissions import Enum_Permissions_Crafty
|
||||
from app.classes.minecraft.serverjars import server_jar_obj
|
||||
from app.classes.shared.helpers import helper
|
||||
import libgravatar
|
||||
import requests
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@ -21,8 +21,8 @@ try:
|
||||
import bleach
|
||||
|
||||
except ModuleNotFoundError as e:
|
||||
logger.critical("Import Error: Unable to load {} module".format(e.name), exc_info=True)
|
||||
console.critical("Import Error: Unable to load {} module".format(e.name))
|
||||
logger.critical(f"Import Error: Unable to load {e.name} module", exc_info=True)
|
||||
console.critical(f"Import Error: Unable to load {e.name} module")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
@ -30,6 +30,7 @@ class ServerHandler(BaseHandler):
|
||||
|
||||
@tornado.web.authenticated
|
||||
def get(self, page):
|
||||
# pylint: disable=unused-variable
|
||||
api_key, token_data, exec_user = self.current_user
|
||||
superuser = exec_user['superuser']
|
||||
if api_key is not None:
|
||||
@ -120,6 +121,7 @@ class ServerHandler(BaseHandler):
|
||||
|
||||
@tornado.web.authenticated
|
||||
def post(self, page):
|
||||
# pylint: disable=unused-variable
|
||||
api_key, token_data, exec_user = self.current_user
|
||||
superuser = exec_user['superuser']
|
||||
if api_key is not None:
|
||||
@ -152,7 +154,7 @@ class ServerHandler(BaseHandler):
|
||||
name_counter = 1
|
||||
while is_name_used(new_server_name):
|
||||
name_counter += 1
|
||||
new_server_name = server_data.get('server_name') + " (Copy {})".format(name_counter)
|
||||
new_server_name = server_data.get('server_name') + f" (Copy {name_counter})"
|
||||
|
||||
new_server_uuid = helper.create_uuid()
|
||||
while os.path.exists(os.path.join(helper.servers_dir, new_server_uuid)):
|
||||
@ -167,12 +169,17 @@ class ServerHandler(BaseHandler):
|
||||
new_server_command = str(server_data.get('execution_command')).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'))).replace(server_uuid, new_server_uuid)
|
||||
auto_start = server_data.get('auto_start')
|
||||
auto_start_delay = server_data.get('auto_start_delay')
|
||||
crash_detection = server_data.get('crash_detection')
|
||||
server_port = server_data.get('server_port')
|
||||
|
||||
self.controller.servers.create_server(new_server_name, new_server_uuid, new_server_path, "", new_server_command, new_executable, new_server_log_file, stop_command, server_port)
|
||||
self.controller.servers.create_server(new_server_name,
|
||||
new_server_uuid,
|
||||
new_server_path,
|
||||
"",
|
||||
new_server_command,
|
||||
new_executable,
|
||||
new_server_log_file,
|
||||
stop_command,
|
||||
server_port)
|
||||
|
||||
self.controller.init_all_servers()
|
||||
|
||||
@ -213,7 +220,7 @@ class ServerHandler(BaseHandler):
|
||||
|
||||
new_server_id = self.controller.import_jar_server(server_name, import_server_path,import_server_jar, min_mem, max_mem, port)
|
||||
self.controller.management.add_to_audit_log(exec_user['user_id'],
|
||||
"imported a jar server named \"{}\"".format(server_name), # Example: Admin imported a server named "old creative"
|
||||
f"imported a jar server named \"{server_name}\"", # Example: Admin imported a server named "old creative"
|
||||
new_server_id,
|
||||
self.get_remote_ip())
|
||||
elif import_type == 'import_zip':
|
||||
@ -226,10 +233,11 @@ class ServerHandler(BaseHandler):
|
||||
|
||||
new_server_id = self.controller.import_zip_server(server_name, zip_path, import_server_jar, min_mem, max_mem, port)
|
||||
if new_server_id == "false":
|
||||
self.redirect("/panel/error?error=Zip file not accessible! You can fix this permissions issue with sudo chown -R crafty:crafty {} And sudo chmod 2775 -R {}".format(import_server_path, import_server_path))
|
||||
self.redirect("/panel/error?error=Zip file not accessible! You can fix this permissions issue with" +
|
||||
f"sudo chown -R crafty:crafty {import_server_path} And sudo chmod 2775 -R {import_server_path}")
|
||||
return
|
||||
self.controller.management.add_to_audit_log(exec_user['user_id'],
|
||||
"imported a zip server named \"{}\"".format(server_name), # Example: Admin imported a server named "old creative"
|
||||
f"imported a zip server named \"{server_name}\"", # Example: Admin imported a server named "old creative"
|
||||
new_server_id,
|
||||
self.get_remote_ip())
|
||||
#deletes temp dir
|
||||
@ -243,7 +251,8 @@ class ServerHandler(BaseHandler):
|
||||
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)
|
||||
self.controller.management.add_to_audit_log(exec_user['user_id'],
|
||||
"created a {} {} server named \"{}\"".format(server_version, str(server_type).capitalize(), server_name), # Example: Admin created a 1.16.5 Bukkit server named "survival"
|
||||
f"created a {server_version} {str(server_type).capitalize()} server named \"{server_name}\"",
|
||||
# Example: Admin created a 1.16.5 Bukkit server named "survival"
|
||||
new_server_id,
|
||||
self.get_remote_ip())
|
||||
|
||||
@ -251,7 +260,7 @@ class ServerHandler(BaseHandler):
|
||||
if len(captured_roles) == 0:
|
||||
if not superuser:
|
||||
new_server_uuid = self.controller.servers.get_server_data_by_id(new_server_id).get("server_uuid")
|
||||
role_id = self.controller.roles.add_role("Creator of Server with uuid={}".format(new_server_uuid))
|
||||
role_id = self.controller.roles.add_role(f"Creator of Server with uuid={new_server_uuid}")
|
||||
self.controller.server_perms.add_role_server(new_server_id, role_id, "11111111")
|
||||
self.controller.users.add_role_to_user(exec_user["user_id"], role_id)
|
||||
self.controller.crafty_perms.add_server_creation(exec_user["user_id"])
|
||||
@ -264,8 +273,11 @@ class ServerHandler(BaseHandler):
|
||||
self.controller.stats.record_stats()
|
||||
self.redirect("/panel/dashboard")
|
||||
|
||||
try:
|
||||
self.render(
|
||||
template,
|
||||
data=page_data,
|
||||
translate=self.translator.translate,
|
||||
)
|
||||
except RuntimeError:
|
||||
self.redirect('/panel/dashboard')
|
||||
|
@ -1,9 +1,5 @@
|
||||
from typing import ( Optional )
|
||||
import tornado.web
|
||||
from typing import (
|
||||
Optional
|
||||
)
|
||||
|
||||
from app.classes.shared.console import console
|
||||
|
||||
class CustomStaticHandler(tornado.web.StaticFileHandler):
|
||||
def validate_absolute_path(self, root: str, absolute_path: str) -> Optional[str]:
|
||||
|
@ -1,27 +1,10 @@
|
||||
from re import template
|
||||
import sys
|
||||
import json
|
||||
import logging
|
||||
import tornado.web
|
||||
import tornado.escape
|
||||
import requests
|
||||
|
||||
from app.classes.shared.helpers import helper
|
||||
from app.classes.web.base_handler import BaseHandler
|
||||
from app.classes.shared.console import console
|
||||
from app.classes.shared.main_models import fn
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
try:
|
||||
import bleach
|
||||
|
||||
except ModuleNotFoundError as e:
|
||||
logger.critical("Import Error: Unable to load {} module".format(e.name), exc_info=True)
|
||||
console.critical("Import Error: Unable to load {} module".format(e.name))
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
class StatusHandler(BaseHandler):
|
||||
def get(self):
|
||||
page_data = {}
|
||||
|
@ -3,10 +3,6 @@ import sys
|
||||
import json
|
||||
import asyncio
|
||||
import logging
|
||||
import threading
|
||||
|
||||
from app.classes.shared.console import console
|
||||
from app.classes.shared.helpers import helper
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@ -26,18 +22,18 @@ try:
|
||||
from app.classes.web.api_handler import ServersStats, NodeStats
|
||||
from app.classes.web.websocket_handler import SocketHandler
|
||||
from app.classes.web.static_handler import CustomStaticHandler
|
||||
from app.classes.shared.translation import translation
|
||||
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
|
||||
from app.classes.shared.translation import translation
|
||||
from app.classes.shared.console import console
|
||||
from app.classes.shared.helpers import helper
|
||||
|
||||
except ModuleNotFoundError as e:
|
||||
logger.critical("Import Error: Unable to load {} module".format(e, e.name))
|
||||
console.critical("Import Error: Unable to load {} module".format(e, e.name))
|
||||
logger.critical(f"Import Error: Unable to load {e.name} module", exc_info=True)
|
||||
console.critical(f"Import Error: Unable to load {e.name} module")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
|
||||
class Webserver:
|
||||
|
||||
def __init__(self, controller, tasks_manager):
|
||||
@ -48,7 +44,6 @@ class Webserver:
|
||||
self.tasks_manager = tasks_manager
|
||||
self._asyncio_patch()
|
||||
|
||||
|
||||
@staticmethod
|
||||
def log_function(handler):
|
||||
|
||||
@ -57,6 +52,7 @@ class Webserver:
|
||||
'Method': handler.request.method,
|
||||
'URL': handler.request.uri,
|
||||
'Remote_IP': handler.request.remote_ip,
|
||||
# pylint: disable=consider-using-f-string
|
||||
'Elapsed_Time': '%.2fms' % (handler.request.request_time() * 1000)
|
||||
}
|
||||
|
||||
@ -74,12 +70,12 @@ class Webserver:
|
||||
"""
|
||||
logger.debug("Checking if asyncio patch is required")
|
||||
if sys.platform.startswith("win") and sys.version_info >= (3, 8):
|
||||
# pylint: disable=reimported,import-outside-toplevel,redefined-outer-name
|
||||
import asyncio
|
||||
try:
|
||||
from asyncio import WindowsSelectorEventLoopPolicy
|
||||
except ImportError:
|
||||
logger.debug("asyncio patch isn't required")
|
||||
pass # Can't assign a policy which doesn't exist.
|
||||
logger.debug("asyncio patch isn't required") # Can't assign a policy which doesn't exist.
|
||||
else:
|
||||
if not isinstance(asyncio.get_event_loop_policy(), WindowsSelectorEventLoopPolicy):
|
||||
asyncio.set_event_loop_policy(WindowsSelectorEventLoopPolicy())
|
||||
@ -110,7 +106,7 @@ class Webserver:
|
||||
'keyfile': os.path.join(helper.config_dir, 'web', 'certs', 'commander.key.pem'),
|
||||
}
|
||||
|
||||
logger.info("Starting Web Server on ports http:{} https:{}".format(http_port, https_port))
|
||||
logger.info(f"Starting Web Server on ports http:{http_port} https:{https_port}")
|
||||
|
||||
asyncio.set_event_loop(asyncio.new_event_loop())
|
||||
|
||||
@ -176,8 +172,8 @@ class Webserver:
|
||||
self.HTTPS_Server = tornado.httpserver.HTTPServer(app, ssl_options=cert_objects)
|
||||
self.HTTPS_Server.listen(https_port)
|
||||
|
||||
logger.info("https://{}:{} is up and ready for connections.".format(helper.get_local_ip(), https_port))
|
||||
console.info("https://{}:{} is up and ready for connections.".format(helper.get_local_ip(), https_port))
|
||||
logger.info(f"https://{helper.get_local_ip()}:{https_port} is up and ready for connections.")
|
||||
console.info(f"https://{helper.get_local_ip()}:{https_port} is up and ready for connections.")
|
||||
|
||||
console.info("Server Init Complete: Listening For Connections:")
|
||||
|
@ -1,16 +1,20 @@
|
||||
from app.classes.shared.main_controller import Controller
|
||||
import logging
|
||||
import os
|
||||
import time
|
||||
|
||||
import tornado.options
|
||||
import tornado.web
|
||||
import tornado.httpserver
|
||||
from tornado.options import options
|
||||
from app.classes.models.server_permissions import Enum_Permissions_Server
|
||||
|
||||
from app.classes.shared.helpers import helper
|
||||
from app.classes.web.websocket_helper import websocket_helper
|
||||
from app.classes.shared.console import console
|
||||
import logging
|
||||
import os
|
||||
import json
|
||||
import time
|
||||
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
|
||||
|
||||
from app.classes.models.server_permissions import Enum_Permissions_Server
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@ -18,7 +22,7 @@ logger = logging.getLogger(__name__)
|
||||
MAX_STREAMED_SIZE = 1024 * 1024 * 1024
|
||||
|
||||
@tornado.web.stream_request_body
|
||||
class UploadHandler(tornado.web.RequestHandler):
|
||||
class UploadHandler(BaseHandler):
|
||||
|
||||
# noinspection PyAttributeOutsideInit
|
||||
def initialize(self, controller: Controller=None, tasks_manager=None, translator=None):
|
||||
@ -28,19 +32,21 @@ class UploadHandler(tornado.web.RequestHandler):
|
||||
|
||||
def prepare(self):
|
||||
self.do_upload = True
|
||||
# pylint: disable=unused-variable
|
||||
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']
|
||||
|
||||
if superuser:
|
||||
exec_user_crafty_permissions = self.controller.crafty_perms.list_defined_crafty_permissions()
|
||||
exec_user_server_permissions = self.controller.server_perms.list_defined_permissions()
|
||||
elif api_key is not None:
|
||||
exec_user_crafty_permissions = self.controller.crafty_perms.get_api_key_permissions_list(api_key)
|
||||
exec_user_server_permissions = self.controller.server_perms.get_api_key_permissions_list(api_key, server_id)
|
||||
else:
|
||||
exec_user_crafty_permissions = self.controller.crafty_perms.get_crafty_permissions_list(
|
||||
exec_user["user_id"])
|
||||
exec_user_server_permissions = self.controller.server_perms.get_user_id_permissions_list(
|
||||
exec_user["user_id"], server_id)
|
||||
|
||||
server_id = self.request.headers.get('X-ServerId', None)
|
||||
|
||||
@ -54,7 +60,7 @@ class UploadHandler(tornado.web.RequestHandler):
|
||||
console.warning('Server ID not found in upload handler call')
|
||||
self.do_upload = False
|
||||
|
||||
if Enum_Permissions_Server.Files not in exec_user_crafty_permissions:
|
||||
if Enum_Permissions_Server.Files not in exec_user_server_permissions:
|
||||
logger.warning(f'User {user_id} tried to upload a file to {server_id} without permissions!')
|
||||
console.warning(f'User {user_id} tried to upload a file to {server_id} without permissions!')
|
||||
self.do_upload = False
|
||||
@ -73,7 +79,7 @@ class UploadHandler(tornado.web.RequestHandler):
|
||||
try:
|
||||
self.f = open(full_path, "wb")
|
||||
except Exception as e:
|
||||
logger.error("Upload failed with error: {}".format(e))
|
||||
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)
|
||||
@ -94,6 +100,6 @@ class UploadHandler(tornado.web.RequestHandler):
|
||||
websocket_helper.broadcast('close_upload_box', 'error')
|
||||
self.finish('error')
|
||||
|
||||
def data_received(self, data):
|
||||
def data_received(self, chunk):
|
||||
if self.do_upload:
|
||||
self.f.write(data)
|
||||
self.f.write(chunk)
|
||||
|
@ -2,13 +2,12 @@ import json
|
||||
import logging
|
||||
import asyncio
|
||||
import sys
|
||||
|
||||
from urllib.parse import parse_qsl
|
||||
from app.classes.models.users import Users
|
||||
|
||||
from app.classes.shared.authentication import authentication
|
||||
from app.classes.shared.helpers import helper
|
||||
from app.classes.web.websocket_helper import websocket_helper
|
||||
from app.classes.shared.console import console
|
||||
from app.classes.web.websocket_helper import websocket_helper
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@ -16,8 +15,8 @@ try:
|
||||
import tornado.websocket
|
||||
|
||||
except ModuleNotFoundError as e:
|
||||
logger.critical("Import Error: Unable to load {} module".format(e, e.name))
|
||||
console.critical("Import Error: Unable to load {} module".format(e, e.name))
|
||||
logger.critical(f"Import Error: Unable to load {e.name} module", exc_info=True)
|
||||
console.critical(f"Import Error: Unable to load {e.name} module")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
@ -48,6 +47,7 @@ class SocketHandler(tornado.websocket.WebSocketHandler):
|
||||
def check_auth(self):
|
||||
return authentication.check_bool(self.get_cookie('token'))
|
||||
|
||||
# pylint: disable=arguments-differ
|
||||
def open(self):
|
||||
logger.debug('Checking WebSocket authentication')
|
||||
if self.check_auth():
|
||||
@ -55,7 +55,10 @@ class SocketHandler(tornado.websocket.WebSocketHandler):
|
||||
else:
|
||||
websocket_helper.send_message(self, 'notification', 'Not authenticated for WebSocket connection')
|
||||
self.close()
|
||||
self.controller.management.add_to_audit_log_raw('unknown', 0, 0, 'Someone tried to connect via WebSocket without proper authentication', self.get_remote_ip())
|
||||
self.controller.management.add_to_audit_log_raw('unknown',
|
||||
0, 0,
|
||||
'Someone tried to connect via WebSocket without proper authentication',
|
||||
self.get_remote_ip())
|
||||
websocket_helper.broadcast('notification', 'Someone tried to connect via WebSocket without proper authentication')
|
||||
logger.warning('Someone tried to connect via WebSocket without proper authentication')
|
||||
|
||||
@ -67,23 +70,21 @@ class SocketHandler(tornado.websocket.WebSocketHandler):
|
||||
)))
|
||||
websocket_helper.add_client(self)
|
||||
logger.debug('Opened WebSocket connection')
|
||||
# websocket_helper.broadcast('notification', 'New client connected')
|
||||
|
||||
# pylint: disable=arguments-renamed
|
||||
@staticmethod
|
||||
def on_message(raw_message):
|
||||
|
||||
logger.debug('Got message from WebSocket connection {}'.format(raw_message))
|
||||
logger.debug(f'Got message from WebSocket connection {raw_message}')
|
||||
message = json.loads(raw_message)
|
||||
logger.debug('Event Type: {}, Data: {}'.format(message['event'], message['data']))
|
||||
logger.debug(f"Event Type: {message['event']}, Data: {message['data']}")
|
||||
|
||||
def on_close(self):
|
||||
websocket_helper.remove_client(self)
|
||||
logger.debug('Closed WebSocket connection')
|
||||
# websocket_helper.broadcast('notification', 'Client disconnected')
|
||||
|
||||
async def write_message_int(self, message):
|
||||
self.write_message(message)
|
||||
|
||||
def write_message_helper(self, message):
|
||||
asyncio.run_coroutine_threadsafe(self.write_message_int(message), self.io_loop.asyncio_loop)
|
||||
|
||||
|
@ -1,20 +1,10 @@
|
||||
import json
|
||||
import logging
|
||||
import sys, threading, asyncio
|
||||
|
||||
from app.classes.shared.console import console
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
try:
|
||||
import tornado.ioloop
|
||||
|
||||
except ModuleNotFoundError as e:
|
||||
logger.critical("Import Error: Unable to load {} module".format(e, e.name))
|
||||
console.critical("Import Error: Unable to load {} module".format(e, e.name))
|
||||
sys.exit(1)
|
||||
|
||||
class WebSocketHelper:
|
||||
def __init__(self):
|
||||
self.clients = set()
|
||||
@ -25,18 +15,19 @@ 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):
|
||||
if client.check_auth():
|
||||
message = str(json.dumps({'event': event_type, 'data': data}))
|
||||
client.write_message_helper(message)
|
||||
|
||||
def broadcast(self, event_type: str, data):
|
||||
logger.debug('Sending to {} clients: {}'.format(len(self.clients), json.dumps({'event': event_type, 'data': data})))
|
||||
logger.debug(f"Sending to {len(self.clients)} clients: {json.dumps({'event': event_type, 'data': data})}")
|
||||
for client in self.clients:
|
||||
try:
|
||||
self.send_message(client, event_type, data)
|
||||
except Exception as e:
|
||||
logger.exception('Error catched while sending WebSocket message to {}'.format(client.get_remote_ip()))
|
||||
logger.exception(f'Error caught while sending WebSocket message to {client.get_remote_ip()} {e}')
|
||||
|
||||
def broadcast_page(self, page: str, event_type: str, data):
|
||||
def filter_fn(client):
|
||||
@ -87,13 +78,13 @@ class WebSocketHelper:
|
||||
def broadcast_with_fn(self, filter_fn, event_type: str, data):
|
||||
clients = list(filter(filter_fn, self.clients))
|
||||
|
||||
logger.debug('Sending to {} out of {} clients: {}'.format(len(clients), len(self.clients), json.dumps({'event': event_type, 'data': data})))
|
||||
logger.debug(f"Sending to {len(clients)} out of {len(self.clients)} clients: {json.dumps({'event': event_type, 'data': data})}")
|
||||
|
||||
for client in clients:
|
||||
try:
|
||||
self.send_message(client, event_type, data)
|
||||
except Exception as e:
|
||||
logger.exception('Error catched while sending WebSocket message to {}'.format(client.get_remote_ip()))
|
||||
logger.exception(f'Error catched while sending WebSocket message to {client.get_remote_ip()} {e}')
|
||||
|
||||
def disconnect_all(self):
|
||||
console.info('Disconnecting WebSocket clients')
|
||||
|
@ -2,5 +2,5 @@
|
||||
"major": 4,
|
||||
"minor": 0,
|
||||
"sub": 0,
|
||||
"meta": "alpha.3"
|
||||
"meta": "alpha.3.5"
|
||||
}
|
||||
|
@ -221,10 +221,10 @@
|
||||
</td>
|
||||
<td id="server_running_status_{{server['server_data']['server_id']}}">
|
||||
{% if server['stats']['running'] %}
|
||||
<i class="fas fa-thumbs-up"></i> <span class="text-success">{{ translate('dashboard', 'online',
|
||||
<span class="text-success"><i class="fas fa-signal"></i> {{ translate('dashboard', 'online',
|
||||
data['lang']) }}</span>
|
||||
{% else %}
|
||||
<i class="fas fa-thumbs-down"></i> <span class="text-danger">{{ translate('dashboard', 'offline',
|
||||
<span class="text-danger"><i class="fas fa-ban"></i> {{ translate('dashboard', 'offline',
|
||||
data['lang']) }}</span>
|
||||
{% end %}
|
||||
</td>
|
||||
|
@ -281,7 +281,9 @@
|
||||
"noDeleteFiles": "No, just remove from panel",
|
||||
"sendingDelete": "Deleting Server",
|
||||
"bePatientDelete": "Please be patient while we remove your server from the Crafty panel. This screen will close in a few moments.",
|
||||
"bePatientDeleteFiles" : "Please be patient while we remove your server from the Crafty panel and delete all files. This screen will close in a few moments."
|
||||
"bePatientDeleteFiles" : "Please be patient while we remove your server from the Crafty panel and delete all files. This screen will close in a few moments.",
|
||||
"crashTime": "Crash Timeout",
|
||||
"crashTimeDesc": "How long should we wait before we consider your server as crashed?"
|
||||
},
|
||||
"serverConfigHelp": {
|
||||
"title": "Server Config Area",
|
||||
|
@ -23,9 +23,11 @@ server {
|
||||
ssl_certificate <CERIFICATE_LOCATION>;
|
||||
ssl_certificate_key <KEYFILE_LOCATION>;
|
||||
location / {
|
||||
#This is important for websockets
|
||||
proxy_http_version 1.1;
|
||||
proxy_redirect off;
|
||||
|
||||
#These are important for websockets. They are required for crafty to function properly.
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $http_connection;
|
||||
proxy_set_header X-Forwarded-Proto https;
|
||||
|
45
main.py
45
main.py
@ -1,4 +1,3 @@
|
||||
from cmd import Cmd
|
||||
import os
|
||||
import sys
|
||||
import json
|
||||
@ -6,19 +5,23 @@ import time
|
||||
import argparse
|
||||
import logging.config
|
||||
import signal
|
||||
import threading
|
||||
from app.classes.controllers.management_controller import Management_Controller
|
||||
|
||||
""" Our custom classes / pip packages """
|
||||
from app.classes.shared.console import console
|
||||
from app.classes.shared.helpers import helper
|
||||
if helper.check_file_exists('/.dockerenv'):
|
||||
console.cyan("Docker environment detected!")
|
||||
else:
|
||||
if helper.checkRoot():
|
||||
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.")
|
||||
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.cmd import MainPrompt
|
||||
from app.classes.shared.command import MainPrompt
|
||||
|
||||
|
||||
def do_intro():
|
||||
@ -47,7 +50,7 @@ def setup_logging(debug=True):
|
||||
|
||||
if os.path.exists(logging_config_file):
|
||||
# open our logging config file
|
||||
with open(logging_config_file, 'rt') as f:
|
||||
with open(logging_config_file, 'rt', encoding='utf-8') as f:
|
||||
logging_config = json.load(f)
|
||||
if debug:
|
||||
logging_config['loggers']['']['level'] = 'DEBUG'
|
||||
@ -56,11 +59,11 @@ def setup_logging(debug=True):
|
||||
|
||||
else:
|
||||
logging.basicConfig(level=logging.DEBUG)
|
||||
logging.warning("Unable to read logging config from {}".format(logging_config_file))
|
||||
console.critical("Unable to read logging config from {}".format(logging_config_file))
|
||||
logging.warning(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 """
|
||||
# Our Main Starter
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser("Crafty Controller - A Server Management System")
|
||||
|
||||
@ -81,21 +84,11 @@ if __name__ == '__main__':
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if helper.check_file_exists('/.dockerenv'):
|
||||
console.cyan("Docker environment detected!")
|
||||
else:
|
||||
if helper.checkRoot():
|
||||
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.")
|
||||
sys.exit(0)
|
||||
helper.ensure_logging_setup()
|
||||
|
||||
setup_logging(debug=args.verbose)
|
||||
|
||||
# setting up the logger object
|
||||
logger = logging.getLogger(__name__)
|
||||
console.cyan("Logging set to: {} ".format(logger.level))
|
||||
console.cyan(f"Logging set to: {logger.level}")
|
||||
|
||||
# print our pretty start message
|
||||
do_intro()
|
||||
@ -112,7 +105,8 @@ if __name__ == '__main__':
|
||||
|
||||
if fresh_install:
|
||||
console.debug("Fresh install detected")
|
||||
console.warning("We have detected a fresh install. Please be sure to forward Crafty's port, {}, through your router/firewall if you would like to be able to access Crafty remotely.".format(helper.get_setting('https_port')))
|
||||
console.warning("We have detected a fresh install. Please be sure to forward Crafty's port, " +
|
||||
f"{helper.get_setting('https_port')}, through your router/firewall if you would like to be able to access Crafty remotely.")
|
||||
installer.default_settings()
|
||||
else:
|
||||
console.debug("Existing install detected")
|
||||
@ -144,7 +138,8 @@ if __name__ == '__main__':
|
||||
console.info("Checking Internet. This may take a minute.")
|
||||
|
||||
if not helper.check_internet():
|
||||
console.warning("We have detected the machine running Crafty has no connection to the internet. Client connections to the server may be limited.")
|
||||
console.warning("We have detected the machine running Crafty has no connection to the internet. " +
|
||||
"Client connections to the server may be limited.")
|
||||
|
||||
if not controller.check_system_user():
|
||||
controller.add_system_user()
|
||||
@ -154,7 +149,7 @@ if __name__ == '__main__':
|
||||
project_root = os.path.dirname(__file__)
|
||||
controller.set_project_root(project_root)
|
||||
|
||||
def sigterm_handler(signum, current_stack_frame):
|
||||
def sigterm_handler():
|
||||
print() # for newline
|
||||
logger.info("Recieved SIGTERM, stopping Crafty")
|
||||
console.info("Recieved SIGTERM, stopping Crafty")
|
||||
|
Loading…
Reference in New Issue
Block a user