mirror of
https://github.com/pelican-dev/panel.git
synced 2026-02-16 03:11:10 +03:00
Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4028588621 | ||
|
|
1cd08e2f8d | ||
|
|
dcf5cb3cd3 | ||
|
|
6d69f6ef47 | ||
|
|
78514f9eb4 | ||
|
|
7deed07cd1 | ||
|
|
597196ad3e |
8
.babelrc
Normal file
8
.babelrc
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"presets": ["es2015"],
|
||||
"compact": true,
|
||||
"minified": true,
|
||||
"only": "public/themes/pterodactyl/js/frontend/files/src/*.js",
|
||||
"sourceMaps": "inline",
|
||||
"comments": false
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
# Pelican Panel - Docker Image
|
||||
# Pterodactyl Panel - Docker Image
|
||||
This is a ready to use docker image for the panel.
|
||||
|
||||
## Requirements
|
||||
This docker image requires some additional software to function. The software can either be provided in other containers (see the [docker-compose.yml](https://github.com/pelican-dev/panel/blob/develop/docker-compose.example.yml) as an example) or as existing instances.
|
||||
This docker image requires some additional software to function. The software can either be provided in other containers (see the [docker-compose.yml](docker-compose.yml) as an example) or as existing instances.
|
||||
|
||||
A mysql database is required. We recommend the stock [MariaDB Image](https://hub.docker.com/_/mariadb/) image if you prefer to run it in a docker container. As a non-containerized option we recommend mariadb.
|
||||
|
||||
@@ -12,7 +12,7 @@ You can provide additional settings using a custom `.env` file or by setting the
|
||||
|
||||
## Setup
|
||||
|
||||
Start the docker container and the required dependencies (either provide existing ones or start containers as well, see the [docker-compose.yml](https://github.com/pelican-dev/panel/blob/develop/docker-compose.example.yml) file as an example.
|
||||
Start the docker container and the required dependencies (either provide existing ones or start containers as well, see the [docker-compose.yml](docker-compose.yml) file as an example).
|
||||
|
||||
After the startup is complete you'll need to create a user.
|
||||
If you are running the docker container without docker-compose, use:
|
||||
@@ -27,30 +27,30 @@ docker-compose exec panel php artisan p:user:make
|
||||
## Environment Variables
|
||||
There are multiple environment variables to configure the panel when not providing your own `.env` file, see the following table for details on each available option.
|
||||
|
||||
Note: If your `APP_URL` starts with `https://` you need to provide an `LE_EMAIL` as well so Certificates can be generated.
|
||||
Note: If your `APP_URL` starts with `https://` you need to provide an `LETSENCRYPT_EMAIL` as well so Certificates can be generated.
|
||||
|
||||
| Variable | Description | Required |
|
||||
|-------------------| ------------------------------------------------------------------------------ | -------- |
|
||||
| `APP_URL` | The URL the panel will be reachable with (including protocol) | yes |
|
||||
| `APP_TIMEZONE` | The timezone to use for the panel | yes |
|
||||
| `LE_EMAIL` | The email used for letsencrypt certificate generation | yes |
|
||||
| `DB_HOST` | The host of the mysql instance | yes |
|
||||
| `DB_PORT` | The port of the mysql instance | yes |
|
||||
| `DB_DATABASE` | The name of the mysql database | yes |
|
||||
| `DB_USERNAME` | The mysql user | yes |
|
||||
| `DB_PASSWORD` | The mysql password for the specified user | yes |
|
||||
| `CACHE_STORE` | The cache driver (see [Cache drivers](#cache-drivers) for detais) | yes |
|
||||
| `SESSION_DRIVER` | | yes |
|
||||
| `QUEUE_DRIVER` | | yes |
|
||||
| `REDIS_HOST` | The hostname or IP address of the redis database | yes |
|
||||
| `REDIS_PASSWORD` | The password used to secure the redis database | maybe |
|
||||
| `REDIS_PORT` | The port the redis database is using on the host | maybe |
|
||||
| `MAIL_DRIVER` | The email driver (see [Mail drivers](#mail-drivers) for details) | yes |
|
||||
| `MAIL_FROM` | The email that should be used as the sender email | yes |
|
||||
| `MAIL_HOST` | The host of your mail driver instance | maybe |
|
||||
| `MAIL_PORT` | The port of your mail driver instance | maybe |
|
||||
| `MAIL_USERNAME` | The username for your mail driver | maybe |
|
||||
| `MAIL_PASSWORD` | The password for your mail driver | maybe |
|
||||
| Variable | Description | Required |
|
||||
| ------------------- | ------------------------------------------------------------------------------ | -------- |
|
||||
| `APP_URL` | The URL the panel will be reachable with (including protocol) | yes |
|
||||
| `APP_TIMEZONE` | The timezone to use for the panel | yes |
|
||||
| `LETSENCRYPT_EMAIL` | The email used for letsencrypt certificate generation | yes |
|
||||
| `DB_HOST` | The host of the mysql instance | yes |
|
||||
| `DB_PORT` | The port of the mysql instance | yes |
|
||||
| `DB_DATABASE` | The name of the mysql database | yes |
|
||||
| `DB_USERNAME` | The mysql user | yes |
|
||||
| `DB_PASSWORD` | The mysql password for the specified user | yes |
|
||||
| `CACHE_DRIVER` | The cache driver (see [Cache drivers](#cache-drivers) for detais) | yes |
|
||||
| `SESSION_DRIVER` | | yes |
|
||||
| `QUEUE_DRIVER` | | yes |
|
||||
| `REDIS_HOST` | The hostname or IP address of the redis database | yes |
|
||||
| `REDIS_PASSWORD` | The password used to secure the redis database | maybe |
|
||||
| `REDIS_PORT` | The port the redis database is using on the host | maybe |
|
||||
| `MAIL_DRIVER` | The email driver (see [Mail drivers](#mail-drivers) for details) | yes |
|
||||
| `MAIL_FROM` | The email that should be used as the sender email | yes |
|
||||
| `MAIL_HOST` | The host of your mail driver instance | maybe |
|
||||
| `MAIL_PORT` | The port of your mail driver instance | maybe |
|
||||
| `MAIL_USERNAME` | The username for your mail driver | maybe |
|
||||
| `MAIL_PASSWORD` | The password for your mail driver | maybe |
|
||||
|
||||
|
||||
### Cache drivers
|
||||
@@ -73,4 +73,4 @@ Every driver requires `MAIL_FROM` to be set.
|
||||
| mandrill | [Mandrill](http://www.mandrill.com/) | `MAIL_USERNAME` |
|
||||
| postmark | [Postmark](https://postmarkapp.com/) | `MAIL_USERNAME` |
|
||||
| mailgun | [Mailgun](https://www.mailgun.com/) | `MAIL_USERNAME`, `MAIL_HOST` |
|
||||
| smtp | Any SMTP server can be configured | `MAIL_USERNAME`, `MAIL_HOST`, `MAIL_PASSWORD`, `MAIL_PORT` |
|
||||
| smtp | Any SMTP server can be configured | `MAIL_USERNAME`, `MAIL_HOST`, `MAIL_PASSWORD`, `MAIL_PORT` |
|
||||
@@ -4,34 +4,10 @@
|
||||
# If using CentOS this file should be placed in:
|
||||
# /etc/nginx/conf.d/
|
||||
#
|
||||
|
||||
# The MIT License (MIT)
|
||||
#
|
||||
# Pterodactyl®
|
||||
# Copyright © Dane Everitt <dane@daneeveritt.com> and contributors
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
server_name _;
|
||||
|
||||
|
||||
root /app/public;
|
||||
index index.html index.htm index.php;
|
||||
charset utf-8;
|
||||
@@ -44,18 +20,18 @@ server {
|
||||
location = /robots.txt { access_log off; log_not_found off; }
|
||||
|
||||
access_log off;
|
||||
error_log /var/log/nginx/panel.app-error.log error;
|
||||
error_log /var/log/nginx/pterodactyl.app-error.log error;
|
||||
|
||||
# allow larger file uploads and longer script runtimes
|
||||
client_max_body_size 100m;
|
||||
client_body_timeout 120s;
|
||||
|
||||
|
||||
sendfile off;
|
||||
|
||||
location ~ \.php$ {
|
||||
fastcgi_split_path_info ^(.+\.php)(/.+)$;
|
||||
# the fastcgi_pass path needs to be changed accordingly when using CentOS
|
||||
fastcgi_pass 127.0.0.1:9000;
|
||||
fastcgi_pass unix:/var/run/php/php-fpm7.2.sock;
|
||||
fastcgi_index index.php;
|
||||
include fastcgi_params;
|
||||
fastcgi_param PHP_VALUE "upload_max_filesize = 100M \n post_max_size=100M";
|
||||
@@ -14,13 +14,13 @@ server {
|
||||
root /app/public;
|
||||
index index.php;
|
||||
|
||||
access_log /var/log/nginx/panel.app-access.log;
|
||||
error_log /var/log/nginx/panel.app-error.log error;
|
||||
access_log /var/log/nginx/pterodactyl.app-access.log;
|
||||
error_log /var/log/nginx/pterodactyl.app-error.log error;
|
||||
|
||||
# allow larger file uploads and longer script runtimes
|
||||
client_max_body_size 100m;
|
||||
client_body_timeout 120s;
|
||||
|
||||
|
||||
sendfile off;
|
||||
|
||||
# strengthen ssl security
|
||||
@@ -30,7 +30,7 @@ server {
|
||||
ssl_prefer_server_ciphers on;
|
||||
ssl_session_cache shared:SSL:10m;
|
||||
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:ECDHE-RSA-AES128-GCM-SHA256:AES256+EECDH:DHE-RSA-AES128-GCM-SHA256:AES256+EDH:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4";
|
||||
|
||||
|
||||
# See the link below for more SSL information:
|
||||
# https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html
|
||||
#
|
||||
@@ -49,7 +49,7 @@ server {
|
||||
|
||||
location ~ \.php$ {
|
||||
fastcgi_split_path_info ^(.+\.php)(/.+)$;
|
||||
fastcgi_pass 127.0.0.1:9000;
|
||||
fastcgi_pass unix:/var/run/php/php-fpm7.2.sock;
|
||||
fastcgi_index index.php;
|
||||
include fastcgi_params;
|
||||
fastcgi_param PHP_VALUE "upload_max_filesize = 100M \n post_max_size=100M";
|
||||
@@ -67,4 +67,4 @@ server {
|
||||
location ~ /\.ht {
|
||||
deny all;
|
||||
}
|
||||
}
|
||||
}
|
||||
70
.dev/docker/entrypoint.sh
Normal file
70
.dev/docker/entrypoint.sh
Normal file
@@ -0,0 +1,70 @@
|
||||
#!/bin/ash
|
||||
## Ensure we are in /app
|
||||
|
||||
cd /app
|
||||
|
||||
mkdir -p /var/log/panel/logs/ /var/log/supervisord/ /var/log/nginx/ /var/log/php7/ \
|
||||
&& rmdir /app/storage/logs/ \
|
||||
&& chmod 777 /var/log/panel/logs/ \
|
||||
&& ln -s /var/log/panel/logs/ /app/storage/
|
||||
|
||||
## check for .env file and generate app keys if missing
|
||||
if [ -f /app/var/.env ]; then
|
||||
echo "external vars exist."
|
||||
rm /app/.env
|
||||
|
||||
ln -s /app/var/.env /app/
|
||||
else
|
||||
echo "external vars don't exist."
|
||||
rm /app/.env
|
||||
touch /app/var/.env
|
||||
|
||||
## manually generate a key because key generate --force fails
|
||||
echo -e "Generating key."
|
||||
APP_KEY=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1)
|
||||
echo -e "Generated app key: $APP_KEY"
|
||||
echo -e "APP_KEY=$APP_KEY" > /app/var/.env
|
||||
|
||||
ln -s /app/var/.env /app/
|
||||
fi
|
||||
|
||||
echo "Checking if https is required."
|
||||
if [ -f /etc/nginx/conf.d/default.conf ]; then
|
||||
echo "Using nginx config already in place."
|
||||
else
|
||||
echo "Checking if letsencrypt email is set."
|
||||
if [ -z $LE_EMAIL ]; then
|
||||
echo "No letsencrypt email is set Failing to http."
|
||||
cp .dev/docker/default.conf /etc/nginx/conf.d/default.conf
|
||||
|
||||
else
|
||||
echo "writing ssl config"
|
||||
cp .dev/docker/default_ssl.conf /etc/nginx/conf.d/default.conf
|
||||
echo "updating ssl config for domain"
|
||||
sed -i "s|<domain>|$(echo $APP_URL | sed 's~http[s]*://~~g')|g" /etc/nginx/conf.d/default.conf
|
||||
echo "generating certs"
|
||||
certbot certonly -d $(echo $APP_URL | sed 's~http[s]*://~~g') --standalone -m $LE_EMAIL --agree-tos -n
|
||||
fi
|
||||
fi
|
||||
|
||||
## check for DB up before starting the panel
|
||||
echo "Checking database status."
|
||||
until nc -z -v -w30 $DB_HOST 3306
|
||||
|
||||
do
|
||||
echo "Waiting for database connection..."
|
||||
# wait for 5 seconds before check again
|
||||
sleep 5
|
||||
done
|
||||
|
||||
## make sure the db is set up
|
||||
echo -e "Migrating and Seeding D.B"
|
||||
php artisan migrate --force
|
||||
php artisan db:seed --force
|
||||
|
||||
## start cronjobs for the queue
|
||||
echo -e "Starting cron jobs."
|
||||
crond -L /var/log/crond -l 5
|
||||
|
||||
echo -e "Starting supervisord."
|
||||
exec "$@"
|
||||
@@ -20,20 +20,20 @@ supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
|
||||
serverurl=unix:///tmp/supervisor.sock ; use a unix:// URL for a unix socket
|
||||
|
||||
[program:php-fpm]
|
||||
command=/usr/local/sbin/php-fpm -F
|
||||
command=/usr/sbin/php-fpm7 -F
|
||||
autostart=true
|
||||
autorestart=true
|
||||
|
||||
[program:queue-worker]
|
||||
command=/usr/local/bin/php /var/www/html/artisan queue:work --tries=3
|
||||
user=www-data
|
||||
command=/usr/bin/php /app/artisan queue:work --queue=high,standard,low --sleep=3 --tries=3
|
||||
user=nginx
|
||||
autostart=true
|
||||
autorestart=true
|
||||
|
||||
[program:caddy]
|
||||
command=caddy run --config /etc/caddy/Caddyfile --adapter caddyfile
|
||||
autostart=%(ENV_SUPERVISORD_CADDY)s
|
||||
autorestart=%(ENV_SUPERVISORD_CADDY)s
|
||||
[program:nginx]
|
||||
command=/usr/sbin/nginx -g 'daemon off;'
|
||||
autostart=true
|
||||
autorestart=true
|
||||
priority=10
|
||||
stdout_events_enabled=true
|
||||
stderr_events_enabled=true
|
||||
stderr_events_enabled=true
|
||||
@@ -1,9 +1,9 @@
|
||||
[www]
|
||||
[pterodactyl]
|
||||
|
||||
user = nginx
|
||||
group = nginx
|
||||
|
||||
listen = 127.0.0.1:9000
|
||||
listen = /var/run/php/php-fpm7.2.sock
|
||||
listen.owner = nginx
|
||||
listen.group = nginx
|
||||
listen.mode = 0750
|
||||
39
.dev/vagrant/.env.vagrant
Normal file
39
.dev/vagrant/.env.vagrant
Normal file
@@ -0,0 +1,39 @@
|
||||
APP_ENV=develop
|
||||
APP_DEBUG=true
|
||||
APP_KEY=SomeRandomString3232RandomString
|
||||
APP_THEME=pterodactyl
|
||||
APP_TIMEZONE=UTC
|
||||
APP_CLEAR_TASKLOG=720
|
||||
APP_DELETE_MINUTES=10
|
||||
APP_URL=http://192.168.50.2/
|
||||
|
||||
DB_HOST=localhost
|
||||
DB_PORT=3306
|
||||
DB_DATABASE=panel
|
||||
DB_USERNAME=pterodactyl
|
||||
DB_PASSWORD=pterodactyl
|
||||
|
||||
CACHE_DRIVER=memcached
|
||||
MEMCACHED_HOST=127.0.0.1
|
||||
SESSION_DRIVER=database
|
||||
|
||||
MAIL_DRIVER=smtp
|
||||
MAIL_HOST=127.0.0.1
|
||||
MAIL_PORT=1025
|
||||
MAIL_USERNAME=
|
||||
MAIL_PASSWORD=
|
||||
MAIL_ENCRYPTION=
|
||||
MAIL_FROM=support@pterodactyl.io
|
||||
|
||||
API_PREFIX=api
|
||||
API_VERSION=v1
|
||||
API_DEBUG=true
|
||||
|
||||
QUEUE_DRIVER=database
|
||||
QUEUE_HIGH=high
|
||||
QUEUE_STANDARD=standard
|
||||
QUEUE_LOW=low
|
||||
|
||||
SQS_KEY=aws-public
|
||||
SQS_SECRET=aws-secret
|
||||
SQS_QUEUE_PREFIX=aws-queue-prefix
|
||||
13
.dev/vagrant/mailhog.service
Normal file
13
.dev/vagrant/mailhog.service
Normal file
@@ -0,0 +1,13 @@
|
||||
[Unit]
|
||||
Description=Mailhog
|
||||
|
||||
[Service]
|
||||
# On some systems the user and group might be different.
|
||||
# Some systems use `apache` as the user and group.
|
||||
User=www-data
|
||||
Group=www-data
|
||||
Restart=on-failure
|
||||
ExecStart=/usr/bin/mailhog
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
189
.dev/vagrant/mariadb.cnf
Normal file
189
.dev/vagrant/mariadb.cnf
Normal file
@@ -0,0 +1,189 @@
|
||||
# MariaDB database server configuration file.
|
||||
#
|
||||
# You can copy this file to one of:
|
||||
# - "/etc/mysql/my.cnf" to set global options,
|
||||
# - "~/.my.cnf" to set user-specific options.
|
||||
#
|
||||
# One can use all long options that the program supports.
|
||||
# Run program with --help to get a list of available options and with
|
||||
# --print-defaults to see which it would actually understand and use.
|
||||
#
|
||||
# For explanations see
|
||||
# http://dev.mysql.com/doc/mysql/en/server-system-variables.html
|
||||
|
||||
# This will be passed to all mysql clients
|
||||
# It has been reported that passwords should be enclosed with ticks/quotes
|
||||
# escpecially if they contain "#" chars...
|
||||
# Remember to edit /etc/mysql/debian.cnf when changing the socket location.
|
||||
[client]
|
||||
port = 3306
|
||||
socket = /var/run/mysqld/mysqld.sock
|
||||
|
||||
# Here is entries for some specific programs
|
||||
# The following values assume you have at least 32M ram
|
||||
|
||||
# This was formally known as [safe_mysqld]. Both versions are currently parsed.
|
||||
[mysqld_safe]
|
||||
socket = /var/run/mysqld/mysqld.sock
|
||||
nice = 0
|
||||
|
||||
[mysqld]
|
||||
#
|
||||
# * Basic Settings
|
||||
#
|
||||
user = mysql
|
||||
pid-file = /var/run/mysqld/mysqld.pid
|
||||
socket = /var/run/mysqld/mysqld.sock
|
||||
port = 3306
|
||||
basedir = /usr
|
||||
datadir = /var/lib/mysql
|
||||
tmpdir = /tmp
|
||||
lc_messages_dir = /usr/share/mysql
|
||||
lc_messages = en_US
|
||||
skip-external-locking
|
||||
#
|
||||
# Instead of skip-networking the default is now to listen only on
|
||||
# localhost which is more compatible and is not less secure.
|
||||
bind-address = 0.0.0.0
|
||||
#
|
||||
# * Fine Tuning
|
||||
#
|
||||
max_connections = 100
|
||||
connect_timeout = 5
|
||||
wait_timeout = 600
|
||||
max_allowed_packet = 16M
|
||||
thread_cache_size = 128
|
||||
sort_buffer_size = 4M
|
||||
bulk_insert_buffer_size = 16M
|
||||
tmp_table_size = 32M
|
||||
max_heap_table_size = 32M
|
||||
#
|
||||
# * MyISAM
|
||||
#
|
||||
# This replaces the startup script and checks MyISAM tables if needed
|
||||
# the first time they are touched. On error, make copy and try a repair.
|
||||
myisam_recover_options = BACKUP
|
||||
key_buffer_size = 128M
|
||||
#open-files-limit = 2000
|
||||
table_open_cache = 400
|
||||
myisam_sort_buffer_size = 512M
|
||||
concurrent_insert = 2
|
||||
read_buffer_size = 2M
|
||||
read_rnd_buffer_size = 1M
|
||||
#
|
||||
# * Query Cache Configuration
|
||||
#
|
||||
# Cache only tiny result sets, so we can fit more in the query cache.
|
||||
query_cache_limit = 128K
|
||||
query_cache_size = 64M
|
||||
# for more write intensive setups, set to DEMAND or OFF
|
||||
#query_cache_type = DEMAND
|
||||
#
|
||||
# * Logging and Replication
|
||||
#
|
||||
# Both location gets rotated by the cronjob.
|
||||
# Be aware that this log type is a performance killer.
|
||||
# As of 5.1 you can enable the log at runtime!
|
||||
#general_log_file = /var/log/mysql/mysql.log
|
||||
#general_log = 1
|
||||
#
|
||||
# Error logging goes to syslog due to /etc/mysql/conf.d/mysqld_safe_syslog.cnf.
|
||||
#
|
||||
# we do want to know about network errors and such
|
||||
log_warnings = 2
|
||||
#
|
||||
# Enable the slow query log to see queries with especially long duration
|
||||
#slow_query_log[={0|1}]
|
||||
slow_query_log_file = /var/log/mysql/mariadb-slow.log
|
||||
long_query_time = 10
|
||||
#log_slow_rate_limit = 1000
|
||||
log_slow_verbosity = query_plan
|
||||
|
||||
#log-queries-not-using-indexes
|
||||
#log_slow_admin_statements
|
||||
#
|
||||
# The following can be used as easy to replay backup logs or for replication.
|
||||
# note: if you are setting up a replication slave, see README.Debian about
|
||||
# other settings you may need to change.
|
||||
#server-id = 1
|
||||
#report_host = master1
|
||||
#auto_increment_increment = 2
|
||||
#auto_increment_offset = 1
|
||||
log_bin = /var/log/mysql/mariadb-bin
|
||||
log_bin_index = /var/log/mysql/mariadb-bin.index
|
||||
# not fab for performance, but safer
|
||||
#sync_binlog = 1
|
||||
expire_logs_days = 10
|
||||
max_binlog_size = 100M
|
||||
# slaves
|
||||
#relay_log = /var/log/mysql/relay-bin
|
||||
#relay_log_index = /var/log/mysql/relay-bin.index
|
||||
#relay_log_info_file = /var/log/mysql/relay-bin.info
|
||||
#log_slave_updates
|
||||
#read_only
|
||||
#
|
||||
# If applications support it, this stricter sql_mode prevents some
|
||||
# mistakes like inserting invalid dates etc.
|
||||
#sql_mode = NO_ENGINE_SUBSTITUTION,TRADITIONAL
|
||||
#
|
||||
# * InnoDB
|
||||
#
|
||||
# InnoDB is enabled by default with a 10MB datafile in /var/lib/mysql/.
|
||||
# Read the manual for more InnoDB related options. There are many!
|
||||
default_storage_engine = InnoDB
|
||||
# you can't just change log file size, requires special procedure
|
||||
#innodb_log_file_size = 50M
|
||||
innodb_buffer_pool_size = 256M
|
||||
innodb_log_buffer_size = 8M
|
||||
innodb_file_per_table = 1
|
||||
innodb_open_files = 400
|
||||
innodb_io_capacity = 400
|
||||
innodb_flush_method = O_DIRECT
|
||||
#
|
||||
# * Security Features
|
||||
#
|
||||
# Read the manual, too, if you want chroot!
|
||||
# chroot = /var/lib/mysql/
|
||||
#
|
||||
# For generating SSL certificates I recommend the OpenSSL GUI "tinyca".
|
||||
#
|
||||
# ssl-ca=/etc/mysql/cacert.pem
|
||||
# ssl-cert=/etc/mysql/server-cert.pem
|
||||
# ssl-key=/etc/mysql/server-key.pem
|
||||
|
||||
#
|
||||
# * Galera-related settings
|
||||
#
|
||||
[galera]
|
||||
# Mandatory settings
|
||||
#wsrep_on=ON
|
||||
#wsrep_provider=
|
||||
#wsrep_cluster_address=
|
||||
#binlog_format=row
|
||||
#default_storage_engine=InnoDB
|
||||
#innodb_autoinc_lock_mode=2
|
||||
#
|
||||
# Allow server to accept connections on all interfaces.
|
||||
#
|
||||
#bind-address=0.0.0.0
|
||||
#
|
||||
# Optional setting
|
||||
#wsrep_slave_threads=1
|
||||
#innodb_flush_log_at_trx_commit=0
|
||||
|
||||
[mysqldump]
|
||||
quick
|
||||
quote-names
|
||||
max_allowed_packet = 16M
|
||||
|
||||
[mysql]
|
||||
#no-auto-rehash # faster start of mysql but no tab completion
|
||||
|
||||
[isamchk]
|
||||
key_buffer = 16M
|
||||
|
||||
#
|
||||
# * IMPORTANT: Additional settings that can override those from this file!
|
||||
# The files must end with '.cnf', otherwise they'll be ignored.
|
||||
#
|
||||
!includedir /etc/mysql/conf.d/
|
||||
17
.dev/vagrant/motd.txt
Normal file
17
.dev/vagrant/motd.txt
Normal file
@@ -0,0 +1,17 @@
|
||||
#####################################################
|
||||
Pterodactyl Panel Vagrant VM
|
||||
|
||||
Install: /var/www/html/pterodactyl
|
||||
Ports:
|
||||
Panel: 80 (50080 on host)
|
||||
MailHog: 8025 (58025 on host)
|
||||
MySQL: 3306 (53306 on host)
|
||||
|
||||
Default panel users:
|
||||
user: admin passwd: Ptero123 (admin user)
|
||||
user: user passwd: Ptero123 (standard user)
|
||||
|
||||
MySQL is accessible using root/pterodactyl or pterodactyl/pterodactyl
|
||||
|
||||
Service for pteroq and mailhog are running
|
||||
#####################################################
|
||||
84
.dev/vagrant/provision.sh
Normal file
84
.dev/vagrant/provision.sh
Normal file
@@ -0,0 +1,84 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "Provisioning development environment for Pterodactyl Panel."
|
||||
cp /var/www/html/pterodactyl/.dev/vagrant/motd.txt /etc/motd
|
||||
chmod -x /etc/update-motd.d/10-help-text /etc/update-motd.d/51-cloudguest
|
||||
|
||||
apt-get install -y software-properties-common > /dev/null
|
||||
|
||||
echo "Add the ondrej/php ppa repository"
|
||||
add-apt-repository -y ppa:ondrej/php > /dev/null
|
||||
echo "Add the mariadb repository"
|
||||
curl -sS https://downloads.mariadb.com/MariaDB/mariadb_repo_setup | bash > /dev/null
|
||||
|
||||
apt-get update > /dev/null
|
||||
|
||||
echo "Install the dependencies"
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
# set the mariadb root password because mariadb asks for it
|
||||
debconf-set-selections <<< 'mariadb-server-5.5 mysql-server/root_password password pterodactyl'
|
||||
debconf-set-selections <<< 'mariadb-server-5.5 mysql-server/root_password_again password pterodactyl'
|
||||
# actually install
|
||||
apt-get install -y php7.2 php7.2-cli php7.2-gd php7.2-mysql php7.2-pdo php7.2-mbstring php7.2-tokenizer php7.2-bcmath php7.2-xml php7.2-fpm php7.2-memcached php7.2-curl php7.2-zip php-xdebug mariadb-server nginx curl tar unzip git memcached > /dev/null
|
||||
|
||||
echo "Install composer"
|
||||
curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
|
||||
|
||||
echo "Install and run mailhog"
|
||||
curl -sL -o /usr/bin/mailhog https://github.com/mailhog/MailHog/releases/download/v1.0.0/MailHog_linux_amd64
|
||||
chmod +x /usr/bin/mailhog
|
||||
cp /var/www/html/pterodactyl/.dev/vagrant/mailhog.service /etc/systemd/system/
|
||||
systemctl enable mailhog.service
|
||||
systemctl start mailhog
|
||||
|
||||
echo "Configure xDebug"
|
||||
cp /var/www/html/pterodactyl/.dev/vagrant/xdebug.ini /etc/php/7.2/mods-available/
|
||||
systemctl restart php7.2-fpm
|
||||
|
||||
echo "Configure nginx"
|
||||
cp /var/www/html/pterodactyl/.dev/vagrant/pterodactyl.conf /etc/nginx/sites-available/
|
||||
rm /etc/nginx/sites-available/default
|
||||
ln -s /etc/nginx/sites-available/pterodactyl.conf /etc/nginx/sites-enabled/pterodactyl.conf
|
||||
systemctl restart nginx
|
||||
|
||||
echo "Setup database"
|
||||
# Replace default config with custom one to bind mysql to 0.0.0.0 to make it accessible from the host
|
||||
cp /var/www/html/pterodactyl/.dev/vagrant/mariadb.cnf /etc/mysql/my.cnf
|
||||
systemctl restart mariadb
|
||||
mysql -u root -ppterodactyl << SQL
|
||||
CREATE DATABASE panel;
|
||||
GRANT ALL PRIVILEGES ON panel.* TO 'pterodactyl'@'%' IDENTIFIED BY 'pterodactyl' WITH GRANT OPTION;
|
||||
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'pterodactyl' WITH GRANT OPTION;
|
||||
FLUSH PRIVILEGES;
|
||||
SQL
|
||||
|
||||
echo "Setup pterodactyl queue worker service"
|
||||
cp /var/www/html/pterodactyl/.dev/vagrant/pteroq.service /etc/systemd/system/
|
||||
systemctl enable pteroq.service
|
||||
|
||||
|
||||
echo "Setup panel with base settings"
|
||||
cp /var/www/html/pterodactyl/.dev/vagrant/.env.vagrant /var/www/html/pterodactyl/.env
|
||||
cd /var/www/html/pterodactyl
|
||||
chmod -R 755 storage/* bootstrap/cache
|
||||
composer install --no-progress
|
||||
php artisan key:generate --force
|
||||
php artisan migrate
|
||||
php artisan db:seed
|
||||
php artisan p:user:make --name-first Test --name-last Admin --username admin --email testadmin@pterodactyl.io --password Ptero123 --admin 1
|
||||
php artisan p:user:make --name-first Test --name-last User --username user --email testuser@pterodactyl.io --password Ptero123 --admin 0
|
||||
|
||||
echo "Add queue cronjob and start queue worker"
|
||||
(crontab -l 2>/dev/null; echo "* * * * * php /var/www/html/pterodactyl/artisan schedule:run >> /dev/null 2>&1") | crontab -
|
||||
systemctl start pteroq
|
||||
|
||||
echo " ----------------"
|
||||
echo "Provisioning is completed."
|
||||
echo "The panel should be available at http://localhost:50080/"
|
||||
echo "You may use the default admin user to login: admin/Ptero123"
|
||||
echo "A normal user has also been created: user/Ptero123"
|
||||
echo "MailHog is available at http://localhost:58025/"
|
||||
echo "Connect to the database using root/pterodactyl or pterodactyl/pterodactyl on localhost:53306"
|
||||
echo "If you want to access the panel using http://pterodactyl.app you can use the vagrant-dns plugin"
|
||||
echo "Install it with 'vagrant plugin install vagrant-dns', then run 'vagrant dns --install' once"
|
||||
echo "On first use you'll have to manually start vagrant-dns with 'vagrant dns --start'"
|
||||
51
.dev/vagrant/pterodactyl.conf
Normal file
51
.dev/vagrant/pterodactyl.conf
Normal file
@@ -0,0 +1,51 @@
|
||||
# If using Ubuntu this file should be placed in:
|
||||
# /etc/nginx/sites-available/
|
||||
#
|
||||
# If using CentOS this file should be placed in:
|
||||
# /etc/nginx/conf.d/
|
||||
#
|
||||
server {
|
||||
listen 80;
|
||||
server_name 0.0.0.0;
|
||||
|
||||
root /var/www/html/pterodactyl/public;
|
||||
index index.html index.htm index.php;
|
||||
charset utf-8;
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ /index.php?$query_string;
|
||||
}
|
||||
|
||||
location = /favicon.ico { access_log off; log_not_found off; }
|
||||
location = /robots.txt { access_log off; log_not_found off; }
|
||||
|
||||
access_log off;
|
||||
error_log /var/log/nginx/pterodactyl.app-error.log error;
|
||||
|
||||
# allow larger file uploads and longer script runtimes
|
||||
client_max_body_size 100m;
|
||||
client_body_timeout 120s;
|
||||
|
||||
sendfile off;
|
||||
|
||||
location ~ \.php$ {
|
||||
fastcgi_split_path_info ^(.+\.php)(/.+)$;
|
||||
# the fastcgi_pass path needs to be changed accordingly when using CentOS
|
||||
fastcgi_pass unix:/var/run/php/php7.2-fpm.sock;
|
||||
fastcgi_index index.php;
|
||||
include fastcgi_params;
|
||||
fastcgi_param PHP_VALUE "upload_max_filesize = 100M \n post_max_size=100M";
|
||||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||
fastcgi_param HTTP_PROXY "";
|
||||
fastcgi_intercept_errors off;
|
||||
fastcgi_buffer_size 16k;
|
||||
fastcgi_buffers 4 16k;
|
||||
fastcgi_connect_timeout 300;
|
||||
fastcgi_send_timeout 300;
|
||||
fastcgi_read_timeout 300;
|
||||
}
|
||||
|
||||
location ~ /\.ht {
|
||||
deny all;
|
||||
}
|
||||
}
|
||||
20
.dev/vagrant/pteroq.service
Normal file
20
.dev/vagrant/pteroq.service
Normal file
@@ -0,0 +1,20 @@
|
||||
# Pterodactyl Queue Worker File
|
||||
# ----------------------------------
|
||||
# File should be placed in:
|
||||
# /etc/systemd/system
|
||||
#
|
||||
# nano /etc/systemd/system/pteroq.service
|
||||
|
||||
[Unit]
|
||||
Description=Pterodactyl Queue Worker
|
||||
|
||||
[Service]
|
||||
# On some systems the user and group might be different.
|
||||
# Some systems use `apache` as the user and group.
|
||||
User=www-data
|
||||
Group=www-data
|
||||
Restart=on-failure
|
||||
ExecStart=/usr/bin/php /var/www/html/pterodactyl/artisan queue:work database --queue=high,standard,low --sleep=3 --tries=3
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
10
.dev/vagrant/xdebug.ini
Normal file
10
.dev/vagrant/xdebug.ini
Normal file
@@ -0,0 +1,10 @@
|
||||
zend_extension=xdebug.so
|
||||
|
||||
xdebug.remote_enable=1
|
||||
xdebug.remote_connect_back=1
|
||||
xdebug.remote_port=9000
|
||||
xdebug.scream=0
|
||||
xdebug.show_local_vars=1
|
||||
xdebug.idekey=PHPSTORM
|
||||
|
||||
xdebug.remote_log=/tmp/xdebug.log
|
||||
@@ -1,10 +0,0 @@
|
||||
.git
|
||||
node_modules
|
||||
vendor
|
||||
database/database.sqlite
|
||||
storage/debugbar/*.json
|
||||
storage/logs/*.log
|
||||
storage/framework/cache/data/*
|
||||
storage/framework/sessions/*
|
||||
storage/framework/testing
|
||||
storage/framework/views/*.php
|
||||
@@ -1,17 +1,12 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
tab_width = 4
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
|
||||
[*.{md,nix,yml,yaml}]
|
||||
indent_size = 2
|
||||
tab_width = 2
|
||||
|
||||
30
.env.example
30
.env.example
@@ -1,7 +1,31 @@
|
||||
APP_ENV=production
|
||||
APP_DEBUG=false
|
||||
APP_KEY=
|
||||
APP_URL=http://panel.test
|
||||
APP_INSTALLED=false
|
||||
APP_TIMEZONE=UTC
|
||||
APP_THEME=pterodactyl
|
||||
APP_TIMEZONE=America/New_York
|
||||
APP_CLEAR_TASKLOG=720
|
||||
APP_DELETE_MINUTES=10
|
||||
APP_ENVIRONMENT_ONLY=true
|
||||
LOG_CHANNEL=daily
|
||||
APP_LOCALE=en
|
||||
|
||||
DB_HOST=127.0.0.1
|
||||
DB_PORT=3306
|
||||
DB_DATABASE=panel
|
||||
DB_USERNAME=pterodactyl
|
||||
DB_PASSWORD=
|
||||
|
||||
HASHIDS_SALT=
|
||||
HASHIDS_LENGTH=8
|
||||
|
||||
MAIL_DRIVER=smtp
|
||||
MAIL_HOST=mailtrap.io
|
||||
MAIL_PORT=2525
|
||||
MAIL_USERNAME=
|
||||
MAIL_PASSWORD=
|
||||
MAIL_ENCRYPTION=tls
|
||||
MAIL_FROM=no-reply@example.com
|
||||
|
||||
QUEUE_HIGH=high
|
||||
QUEUE_STANDARD=standard
|
||||
QUEUE_LOW=low
|
||||
19
.env.travis
Normal file
19
.env.travis
Normal file
@@ -0,0 +1,19 @@
|
||||
APP_ENV=testing
|
||||
APP_DEBUG=true
|
||||
APP_KEY=SomeRandomString3232RandomString
|
||||
APP_THEME=pterodactyl
|
||||
APP_TIMEZONE=UTC
|
||||
APP_URL=http://localhost/
|
||||
|
||||
TESTING_DB_HOST=127.0.0.1
|
||||
TESTING_DB_DATABASE=travis
|
||||
TESTING_DB_USERNAME=root
|
||||
TESTING_DB_PASSWORD=""
|
||||
|
||||
CACHE_DRIVER=array
|
||||
SESSION_DRIVER=array
|
||||
MAIL_DRIVER=array
|
||||
QUEUE_DRIVER=sync
|
||||
|
||||
HASHIDS_SALT=test123
|
||||
APP_ENVIRONMENT_ONLY=true
|
||||
@@ -1,6 +0,0 @@
|
||||
public
|
||||
node_modules
|
||||
resources/views
|
||||
babel.config.js
|
||||
tailwind.config.js
|
||||
webpack.config.js
|
||||
52
.eslintrc.js
52
.eslintrc.js
@@ -1,52 +0,0 @@
|
||||
/** @type {import('eslint').Linter.Config} */
|
||||
module.exports = {
|
||||
parser: '@typescript-eslint/parser',
|
||||
parserOptions: {
|
||||
ecmaVersion: 6,
|
||||
ecmaFeatures: {
|
||||
jsx: true,
|
||||
},
|
||||
project: './tsconfig.json',
|
||||
tsconfigRootDir: './',
|
||||
},
|
||||
settings: {
|
||||
react: {
|
||||
pragma: 'React',
|
||||
version: 'detect',
|
||||
},
|
||||
linkComponents: [
|
||||
{ name: 'Link', linkAttribute: 'to' },
|
||||
{ name: 'NavLink', linkAttribute: 'to' },
|
||||
],
|
||||
},
|
||||
env: {
|
||||
browser: true,
|
||||
es6: true,
|
||||
},
|
||||
plugins: ['react', 'react-hooks', 'prettier', '@typescript-eslint'],
|
||||
extends: [
|
||||
// 'standard',
|
||||
'eslint:recommended',
|
||||
'plugin:react/recommended',
|
||||
'plugin:@typescript-eslint/recommended',
|
||||
'plugin:jest-dom/recommended',
|
||||
],
|
||||
rules: {
|
||||
eqeqeq: 'error',
|
||||
'prettier/prettier': ['error', {}, { usePrettierrc: true }],
|
||||
// TypeScript can infer this significantly better than eslint ever can.
|
||||
'react/prop-types': 0,
|
||||
'react/display-name': 0,
|
||||
'@typescript-eslint/no-explicit-any': 0,
|
||||
'@typescript-eslint/no-non-null-assertion': 0,
|
||||
// 'react/no-unknown-property': ['error', { ignore: ['css'] }],
|
||||
// This setup is required to avoid a spam of errors when running eslint about React being
|
||||
// used before it is defined.
|
||||
//
|
||||
// @see https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-use-before-define.md#how-to-use
|
||||
'no-use-before-define': 0,
|
||||
'@typescript-eslint/no-use-before-define': 'warn',
|
||||
'@typescript-eslint/no-unused-vars': ['warn', { argsIgnorePattern: '^_', varsIgnorePattern: '^_' }],
|
||||
'@typescript-eslint/ban-ts-comment': ['error', { 'ts-expect-error': 'allow-with-description' }],
|
||||
},
|
||||
};
|
||||
2
.github/FUNDING.yml
vendored
2
.github/FUNDING.yml
vendored
@@ -1,2 +0,0 @@
|
||||
github: pelican-dev
|
||||
custom: [https://hub.pelican.dev/donors]
|
||||
35
.github/ISSUE_TEMPLATE/---bug-report.md
vendored
Normal file
35
.github/ISSUE_TEMPLATE/---bug-report.md
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
---
|
||||
name: "\U0001F41B Bug Report"
|
||||
about: For reporting code or design bugs with the software. DO NOT REPORT APACHE/NGINX/PHP CONFIGURATION ISSUES.
|
||||
|
||||
---
|
||||
|
||||
DO NOT REPORT ISSUES CONFIGURING: SSL, PHP, APACHE, NGINX, YOUR MACHINE, SSH, SFTP, ETC. ON THIS GITHUB TRACKER.
|
||||
|
||||
For assistance installating this software, as well as debugging issues with dependencies, please use our discord server: https://discord.gg/pterodactyl
|
||||
|
||||
You MUST complete all of the below information when reporting a bug, failure to do so will result in closure of your issue. PLEASE stop spamming our tracker with "bugs" that are not related to this project.
|
||||
|
||||
**STOP: READ FIRST, AND THEN DELETE THE ABOVE LINES**
|
||||
|
||||
**Background (please complete the following information):**
|
||||
* Panel or Daemon:
|
||||
* Version of Panel/Daemon:
|
||||
* Server's OS:
|
||||
* Your Computer's OS & Browser:
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
Please provide additional information too, depending on what you have issues with:
|
||||
Panel: `php -v` (the php version in use).
|
||||
Daemon: `uname -a` and `docker info` (your kernel version and information regarding docker)
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
4. See error
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen. If applicable, add screenshots or a recording to help explain your problem.
|
||||
17
.github/ISSUE_TEMPLATE/---feature-request.md
vendored
Normal file
17
.github/ISSUE_TEMPLATE/---feature-request.md
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
---
|
||||
name: "\U0001F680 Feature Request"
|
||||
about: Suggest an idea for this project
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
||||
14
.github/ISSUE_TEMPLATE/--installation-help.md
vendored
Normal file
14
.github/ISSUE_TEMPLATE/--installation-help.md
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
---
|
||||
name: "⛔ Installation Help"
|
||||
about: 'Visit our Discord for installation help: https://pterodactyl.io/discord'
|
||||
|
||||
---
|
||||
|
||||
We use GitHub issues only to discuss about Pterodactyl bugs and new features. For
|
||||
this kind of questions about using Pterodactyl, please visit our Discord for assistance: https://pterodactyl.io/discord
|
||||
|
||||
DO NOT REPORT ISSUES CONFIGURING: SSL, PHP, APACHE, NGINX, YOUR MACHINE, SSH, SFTP, ETC. ON THIS GITHUB TRACKER.
|
||||
|
||||
For assistance installating this software, as well as debugging issues with dependencies, please use our discord server: https://discord.gg/pterodactyl
|
||||
|
||||
PLEASE stop spamming our tracker with "bugs" that are not related to this project.
|
||||
85
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
85
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
@@ -1,85 +0,0 @@
|
||||
name: Bug Report
|
||||
description: Something isn't working quite right in the software.
|
||||
labels: [not confirmed]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Bug reports should only be used for reporting issues with how the software works. For assistance installing this software, as well as debugging issues with dependencies, please use our Discord Server.
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Current Behavior
|
||||
description: Please provide a clear & concise description of the issue.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Expected Behavior
|
||||
description: Please describe what you expected to happen.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Steps to Reproduce
|
||||
description: Please be as detailed as possible when providing steps to reproduce, failure to provide steps will result in this issue being closed.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
id: panel-version
|
||||
attributes:
|
||||
label: Panel Version
|
||||
description: Version number of your Panel (latest is not a version)
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
id: wings-version
|
||||
attributes:
|
||||
label: Wings Version
|
||||
description: Version number of your Wings (latest is not a version)
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
id: egg-details
|
||||
attributes:
|
||||
label: Games and/or Eggs Affected
|
||||
description: Please include the specific game(s) or egg(s) you are running into this bug with.
|
||||
placeholder: Minecraft (Paper), Minecraft (Forge)
|
||||
|
||||
- type: input
|
||||
id: docker-image
|
||||
attributes:
|
||||
label: Docker Image
|
||||
description: The specific Docker image you are using for the game(s) above.
|
||||
placeholder: ghcr.io/pelican-dev/yolks:java_17
|
||||
|
||||
- type: textarea
|
||||
id: panel-logs
|
||||
attributes:
|
||||
label: Error Logs
|
||||
description: |
|
||||
Run the following command to collect logs on your system.
|
||||
|
||||
Wings: `sudo wings diagnostics`
|
||||
Panel: `tail -n 150 /var/www/pelican/storage/logs/laravel-$(date +%F).log | curl -X POST -F 'c=@-' paste.pelistuff.com`
|
||||
placeholder: "https://pelipaste.com/a1h6z"
|
||||
render: bash
|
||||
validations:
|
||||
required: false
|
||||
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Is there an existing issue for this?
|
||||
description: Please [search here](https://github.com/pelican-dev/panel/issues) to see if an issue already exists for your problem.
|
||||
options:
|
||||
- label: I have searched the existing issues before opening this issue.
|
||||
required: true
|
||||
- label: I have provided all relevant details, including the specific game and Docker images I am using if this issue is related to running a server.
|
||||
required: true
|
||||
- label: I have checked in the Discord server and believe this is a bug with the software, and not a configuration issue with my specific system.
|
||||
required: true
|
||||
11
.github/ISSUE_TEMPLATE/config.yml
vendored
11
.github/ISSUE_TEMPLATE/config.yml
vendored
@@ -1,11 +0,0 @@
|
||||
blank_issues_enabled: true
|
||||
contact_links:
|
||||
- name: Feature Request
|
||||
url: https://github.com/pelican-dev/panel/discussions
|
||||
about: Suggest a new feature or improvement for the software.
|
||||
- name: Installation Help
|
||||
url: https://pelican.dev/discord
|
||||
about: Please visit our Discord for help with your installation.
|
||||
- name: General Question
|
||||
url: https://pelican.dev/discord
|
||||
about: Please visit our Discord for general questions about Pelican.
|
||||
64
.github/docker/entrypoint.sh
vendored
64
.github/docker/entrypoint.sh
vendored
@@ -1,64 +0,0 @@
|
||||
#!/bin/ash -e
|
||||
|
||||
#mkdir -p /var/log/supervisord/ /var/log/php8/ \
|
||||
|
||||
## check for .env file and generate app keys if missing
|
||||
if [ -f /pelican-data/.env ]; then
|
||||
echo "external vars exist."
|
||||
rm -rf /var/www/html/.env
|
||||
else
|
||||
echo "external vars don't exist."
|
||||
rm -rf /var/www/html/.env
|
||||
touch /pelican-data/.env
|
||||
|
||||
## manually generate a key because key generate --force fails
|
||||
if [ -z $APP_KEY ]; then
|
||||
echo -e "Generating key."
|
||||
APP_KEY=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1)
|
||||
echo -e "Generated app key: $APP_KEY"
|
||||
echo -e "APP_KEY=$APP_KEY" > /pelican-data/.env
|
||||
else
|
||||
echo -e "APP_KEY exists in environment, using that."
|
||||
echo -e "APP_KEY=$APP_KEY" > /pelican-data/.env
|
||||
fi
|
||||
|
||||
## enable installer
|
||||
echo -e "APP_INSTALLED=false" >> /pelican-data/.env
|
||||
fi
|
||||
|
||||
mkdir /pelican-data/database
|
||||
ln -s /pelican-data/.env /var/www/html/
|
||||
ln -s /pelican-data/database/database.sqlite /var/www/html/database/
|
||||
|
||||
if ! grep -q "APP_KEY=" .env || grep -q "APP_KEY=$" .env; then
|
||||
echo "Generating APP_KEY..."
|
||||
php artisan key:generate --force
|
||||
else
|
||||
echo "APP_KEY is already set."
|
||||
fi
|
||||
|
||||
## make sure the db is set up
|
||||
echo -e "Migrating Database"
|
||||
php artisan migrate --force
|
||||
|
||||
echo -e "Optimizing Filament"
|
||||
php artisan filament:optimize
|
||||
|
||||
## start cronjobs for the queue
|
||||
echo -e "Starting cron jobs."
|
||||
crond -L /var/log/crond -l 5
|
||||
|
||||
export SUPERVISORD_CADDY=false
|
||||
|
||||
## disable caddy if SKIP_CADDY is set
|
||||
if [[ -z $SKIP_CADDY ]]; then
|
||||
echo "Starting PHP-FPM and Caddy"
|
||||
export SUPERVISORD_CADDY=true
|
||||
else
|
||||
echo "Starting PHP-FPM only"
|
||||
fi
|
||||
|
||||
chown -R www-data:www-data . /pelican-data/.env /pelican-data/database
|
||||
|
||||
echo "Starting Supervisord"
|
||||
exec "$@"
|
||||
33
.github/workflows/build.yaml
vendored
33
.github/workflows/build.yaml
vendored
@@ -1,33 +0,0 @@
|
||||
name: Build
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- '**'
|
||||
pull_request:
|
||||
branches:
|
||||
- '**'
|
||||
|
||||
jobs:
|
||||
ui:
|
||||
name: UI
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
node-version: [18, 20]
|
||||
steps:
|
||||
- name: Code Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
cache: "yarn"
|
||||
|
||||
- name: Install dependencies
|
||||
run: yarn install --frozen-lockfile
|
||||
|
||||
- name: Build
|
||||
run: yarn build:production
|
||||
215
.github/workflows/ci.yaml
vendored
215
.github/workflows/ci.yaml
vendored
@@ -1,215 +0,0 @@
|
||||
name: Tests
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
mysql:
|
||||
name: MySQL
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
php: [8.2, 8.3]
|
||||
database: ["mysql:8"]
|
||||
services:
|
||||
database:
|
||||
image: ${{ matrix.database }}
|
||||
env:
|
||||
MYSQL_ALLOW_EMPTY_PASSWORD: yes
|
||||
MYSQL_DATABASE: testing
|
||||
ports:
|
||||
- 3306
|
||||
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
|
||||
env:
|
||||
APP_ENV: testing
|
||||
APP_DEBUG: "false"
|
||||
APP_KEY: ThisIsARandomStringForTests12345
|
||||
APP_TIMEZONE: UTC
|
||||
APP_URL: http://localhost/
|
||||
CACHE_DRIVER: array
|
||||
MAIL_MAILER: array
|
||||
SESSION_DRIVER: array
|
||||
QUEUE_CONNECTION: sync
|
||||
DB_CONNECTION: mysql
|
||||
DB_HOST: 127.0.0.1
|
||||
DB_DATABASE: testing
|
||||
DB_USERNAME: root
|
||||
GUZZLE_TIMEOUT: 60
|
||||
GUZZLE_CONNECT_TIMEOUT: 60
|
||||
steps:
|
||||
- name: Code Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Get cache directory
|
||||
id: composer-cache
|
||||
run: |
|
||||
echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ${{ steps.composer-cache.outputs.dir }}
|
||||
key: ${{ runner.os }}-composer-${{ matrix.php }}-${{ hashFiles('**/composer.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-composer-${{ matrix.php }}-
|
||||
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ matrix.php }}
|
||||
extensions: bcmath, curl, gd, mbstring, mysql, openssl, pdo, tokenizer, xml, zip
|
||||
tools: composer:v2
|
||||
coverage: none
|
||||
|
||||
- name: Install dependencies
|
||||
run: composer install --no-interaction --no-suggest --prefer-dist
|
||||
|
||||
- name: Unit tests
|
||||
run: vendor/bin/phpunit tests/Unit
|
||||
env:
|
||||
DB_HOST: UNIT_NO_DB
|
||||
SKIP_MIGRATIONS: true
|
||||
|
||||
- name: Integration tests
|
||||
run: vendor/bin/phpunit tests/Integration
|
||||
env:
|
||||
DB_PORT: ${{ job.services.database.ports[3306] }}
|
||||
DB_USERNAME: root
|
||||
|
||||
mariadb:
|
||||
name: MariaDB
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
php: [8.2, 8.3]
|
||||
database: ["mariadb:10.3", "mariadb:10.11", "mariadb:11.4"]
|
||||
services:
|
||||
database:
|
||||
image: ${{ matrix.database }}
|
||||
env:
|
||||
MYSQL_ALLOW_EMPTY_PASSWORD: yes
|
||||
MYSQL_DATABASE: testing
|
||||
ports:
|
||||
- 3306
|
||||
options: --health-cmd="mariadb-admin ping || mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
|
||||
env:
|
||||
APP_ENV: testing
|
||||
APP_DEBUG: "false"
|
||||
APP_KEY: ThisIsARandomStringForTests12345
|
||||
APP_TIMEZONE: UTC
|
||||
APP_URL: http://localhost/
|
||||
CACHE_DRIVER: array
|
||||
MAIL_MAILER: array
|
||||
SESSION_DRIVER: array
|
||||
QUEUE_CONNECTION: sync
|
||||
DB_CONNECTION: mariadb
|
||||
DB_HOST: 127.0.0.1
|
||||
DB_DATABASE: testing
|
||||
DB_USERNAME: root
|
||||
GUZZLE_TIMEOUT: 60
|
||||
GUZZLE_CONNECT_TIMEOUT: 60
|
||||
steps:
|
||||
- name: Code Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Get cache directory
|
||||
id: composer-cache
|
||||
run: |
|
||||
echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ${{ steps.composer-cache.outputs.dir }}
|
||||
key: ${{ runner.os }}-composer-${{ matrix.php }}-${{ hashFiles('**/composer.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-composer-${{ matrix.php }}-
|
||||
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ matrix.php }}
|
||||
extensions: bcmath, curl, gd, mbstring, mysql, openssl, pdo, tokenizer, xml, zip
|
||||
tools: composer:v2
|
||||
coverage: none
|
||||
|
||||
- name: Install dependencies
|
||||
run: composer install --no-interaction --no-suggest --prefer-dist
|
||||
|
||||
- name: Unit tests
|
||||
run: vendor/bin/phpunit tests/Unit
|
||||
env:
|
||||
DB_HOST: UNIT_NO_DB
|
||||
SKIP_MIGRATIONS: true
|
||||
|
||||
- name: Integration tests
|
||||
run: vendor/bin/phpunit tests/Integration
|
||||
env:
|
||||
DB_PORT: ${{ job.services.database.ports[3306] }}
|
||||
DB_USERNAME: root
|
||||
|
||||
sqlite:
|
||||
name: SQLite
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
php: [8.2, 8.3]
|
||||
env:
|
||||
APP_ENV: testing
|
||||
APP_DEBUG: "false"
|
||||
APP_KEY: ThisIsARandomStringForTests12345
|
||||
APP_TIMEZONE: UTC
|
||||
APP_URL: http://localhost/
|
||||
CACHE_DRIVER: array
|
||||
MAIL_MAILER: array
|
||||
SESSION_DRIVER: array
|
||||
QUEUE_CONNECTION: sync
|
||||
DB_CONNECTION: sqlite
|
||||
DB_DATABASE: testing.sqlite
|
||||
GUZZLE_TIMEOUT: 60
|
||||
GUZZLE_CONNECT_TIMEOUT: 60
|
||||
steps:
|
||||
- name: Code Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Get cache directory
|
||||
id: composer-cache
|
||||
run: |
|
||||
echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ${{ steps.composer-cache.outputs.dir }}
|
||||
key: ${{ runner.os }}-composer-${{ matrix.php }}-${{ hashFiles('**/composer.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-composer-${{ matrix.php }}-
|
||||
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ matrix.php }}
|
||||
extensions: bcmath, curl, gd, mbstring, mysql, openssl, pdo, tokenizer, xml, zip
|
||||
tools: composer:v2
|
||||
coverage: none
|
||||
|
||||
- name: Install dependencies
|
||||
run: composer install --no-interaction --no-suggest --prefer-dist
|
||||
|
||||
- name: Create SQLite file
|
||||
run: touch database/testing.sqlite
|
||||
|
||||
- name: Unit tests
|
||||
run: vendor/bin/phpunit tests/Unit
|
||||
env:
|
||||
DB_HOST: UNIT_NO_DB
|
||||
SKIP_MIGRATIONS: true
|
||||
|
||||
- name: Integration tests
|
||||
run: vendor/bin/phpunit tests/Integration
|
||||
30
.github/workflows/cla.yaml
vendored
30
.github/workflows/cla.yaml
vendored
@@ -1,30 +0,0 @@
|
||||
name: "CLA Assistant"
|
||||
on:
|
||||
issue_comment:
|
||||
types: [created]
|
||||
pull_request_target:
|
||||
types: [opened,closed,synchronize]
|
||||
|
||||
permissions:
|
||||
actions: write
|
||||
contents: read
|
||||
pull-requests: write
|
||||
statuses: write
|
||||
|
||||
jobs:
|
||||
CLAAssistant:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: "CLA Assistant"
|
||||
if: (github.event.comment.body == 'recheck' || github.event.comment.body == 'I have read the CLA Document and I hereby sign the CLA') || github.event_name == 'pull_request_target'
|
||||
uses: contributor-assistant/github-action@v2.4.0
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
PERSONAL_ACCESS_TOKEN: ${{ secrets.CLA_PERSONAL_ACCESS_TOKEN }}
|
||||
with:
|
||||
path-to-signatures: 'version1/cla.json'
|
||||
path-to-document: 'https://github.com/pelican-dev/panel/blob/main/contributor_license_agreement.md'
|
||||
branch: 'main'
|
||||
allowlist: dependabot[bot]
|
||||
remote-organization-name: pelican-dev
|
||||
remote-repository-name: cla-signatures
|
||||
82
.github/workflows/docker-publish.yml
vendored
82
.github/workflows/docker-publish.yml
vendored
@@ -1,82 +0,0 @@
|
||||
name: Docker
|
||||
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
release:
|
||||
types:
|
||||
- published
|
||||
|
||||
jobs:
|
||||
build-and-push:
|
||||
name: Build and Push
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
# Always run against a tag, even if the commit into the tag has [docker skip] within the commit message.
|
||||
if: "!contains(github.ref, 'main') || (!contains(github.event.head_commit.message, 'skip docker') && !contains(github.event.head_commit.message, 'docker skip'))"
|
||||
steps:
|
||||
- name: Code checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Docker metadata
|
||||
id: docker_meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ghcr.io/pelican-dev/panel
|
||||
flavor: |
|
||||
latest=false
|
||||
tags: |
|
||||
type=raw,value=latest,enable=${{ github.event_name == 'release' && github.event.action == 'published' && github.event.release.prerelease == false }}
|
||||
type=ref,event=tag
|
||||
type=ref,event=branch
|
||||
|
||||
- name: Setup QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: Setup Docker buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Get Build Information
|
||||
id: build_info
|
||||
run: |
|
||||
echo "version_tag=${GITHUB_REF/refs\/tags\/v/}" >> $GITHUB_OUTPUT
|
||||
echo "short_sha=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Build and Push (tag)
|
||||
uses: docker/build-push-action@v5
|
||||
if: "github.event_name == 'release' && github.event.action == 'published'"
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile
|
||||
push: true
|
||||
platforms: linux/amd64,linux/arm64
|
||||
build-args: |
|
||||
VERSION=${{ steps.build_info.outputs.version_tag }}
|
||||
labels: ${{ steps.docker_meta.outputs.labels }}
|
||||
tags: ${{ steps.docker_meta.outputs.tags }}
|
||||
|
||||
- name: Build and Push (main)
|
||||
uses: docker/build-push-action@v5
|
||||
if: "github.event_name == 'push' && contains(github.ref, 'main')"
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile
|
||||
push: ${{ github.event_name != 'pull_request' }}
|
||||
platforms: linux/amd64,linux/arm64
|
||||
build-args: |
|
||||
VERSION=dev-${{ steps.build_info.outputs.short_sha }}
|
||||
labels: ${{ steps.docker_meta.outputs.labels }}
|
||||
tags: ${{ steps.docker_meta.outputs.tags }}
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
54
.github/workflows/lint.yaml
vendored
54
.github/workflows/lint.yaml
vendored
@@ -1,54 +0,0 @@
|
||||
name: Lint
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- '**'
|
||||
|
||||
jobs:
|
||||
pint:
|
||||
name: Pint
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Code Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: "8.3"
|
||||
extensions: bcmath, curl, gd, mbstring, mysql, openssl, pdo, tokenizer, xml, zip
|
||||
tools: composer:v2
|
||||
coverage: none
|
||||
|
||||
- name: Setup .env
|
||||
run: cp .env.example .env
|
||||
|
||||
- name: Install dependencies
|
||||
run: composer install --no-interaction --no-progress --prefer-dist
|
||||
|
||||
- name: Pint
|
||||
run: vendor/bin/pint --test
|
||||
phpstan:
|
||||
name: PHPStan
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Code Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: "8.3"
|
||||
extensions: bcmath, curl, gd, mbstring, mysql, openssl, pdo, tokenizer, xml, zip
|
||||
tools: composer:v2
|
||||
coverage: none
|
||||
|
||||
- name: Setup .env
|
||||
run: cp .env.example .env
|
||||
|
||||
- name: Install dependencies
|
||||
run: composer install --no-interaction --no-progress --prefer-dist
|
||||
|
||||
- name: PHPStan
|
||||
run: vendor/bin/phpstan --memory-limit=-1
|
||||
65
.github/workflows/release.yaml
vendored
65
.github/workflows/release.yaml
vendored
@@ -1,65 +0,0 @@
|
||||
name: Release
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "v*"
|
||||
|
||||
jobs:
|
||||
release:
|
||||
name: Release
|
||||
runs-on: ubuntu-22.04
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
steps:
|
||||
- name: Code checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
cache: "yarn"
|
||||
|
||||
- name: Install dependencies
|
||||
run: yarn install --frozen-lockfile
|
||||
|
||||
- name: Build
|
||||
run: yarn build:production
|
||||
|
||||
- name: Create release branch and bump version
|
||||
env:
|
||||
REF: ${{ github.ref }}
|
||||
run: |
|
||||
BRANCH=release/${REF:10}
|
||||
git config --local user.email "github-actions[bot]@users.noreply.github.com"
|
||||
git config --local user.name "github-actions[bot]"
|
||||
git checkout -b $BRANCH
|
||||
git push -u origin $BRANCH
|
||||
sed -i "s/ 'version' => 'canary',/ 'version' => '${REF:11}',/" config/app.php
|
||||
git add config/app.php
|
||||
git commit -m "ci(release): bump version"
|
||||
git push
|
||||
|
||||
- name: Create release archive
|
||||
run: |
|
||||
rm -rf node_modules tests CODE_OF_CONDUCT.md CONTRIBUTING.md flake.lock flake.nix phpunit.xml shell.nix
|
||||
tar -czf panel.tar.gz * .editorconfig .env.example .eslintignore .eslintrc.js .gitignore .prettierrc.json
|
||||
|
||||
- name: Create checksum
|
||||
run: |
|
||||
SUM=`sha256sum panel.tar.gz`
|
||||
echo $SUM > checksum.txt
|
||||
|
||||
- name: Create release
|
||||
id: create_release
|
||||
uses: softprops/action-gh-release@v2
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
draft: true
|
||||
prerelease: ${{ contains(github.ref, 'rc') || contains(github.ref, 'beta') || contains(github.ref, 'alpha') }}
|
||||
files: |
|
||||
panel.tar.gz
|
||||
checksum.txt
|
||||
52
.gitignore
vendored
52
.gitignore
vendored
@@ -1,28 +1,34 @@
|
||||
/.phpunit.cache
|
||||
/node_modules
|
||||
/public/build
|
||||
/public/hot
|
||||
/public/storage
|
||||
/storage/*.key
|
||||
/storage/clockwork/*
|
||||
/vendor
|
||||
*.DS_Store*
|
||||
.env
|
||||
.env.backup
|
||||
.env.production
|
||||
.phpactor.json
|
||||
.phpunit.result.cache
|
||||
Homestead.json
|
||||
Homestead.yaml
|
||||
auth.json
|
||||
npm-debug.log
|
||||
yarn-error.log
|
||||
/.fleet
|
||||
.vagrant/*
|
||||
.vscode/*
|
||||
storage/framework/*
|
||||
/.idea
|
||||
/.vscode
|
||||
/nbproject
|
||||
|
||||
public/assets/manifest.json
|
||||
/database/*.sqlite
|
||||
filament-monaco-editor/
|
||||
_ide_helper*
|
||||
/.phpstorm.meta.php
|
||||
package-lock.json
|
||||
composer.lock
|
||||
node_modules
|
||||
|
||||
_ide_helper_models.php
|
||||
_ide_helper.php
|
||||
|
||||
sami.phar
|
||||
/.sami
|
||||
|
||||
# For local development with docker
|
||||
# Remove if we ever put the Dockerfile in the repo
|
||||
.dockerignore
|
||||
#Dockerfile
|
||||
docker-compose.yml
|
||||
|
||||
# for image related files
|
||||
misc
|
||||
.phpstorm.meta.php
|
||||
.php_cs.cache
|
||||
|
||||
coverage.xml
|
||||
|
||||
# Vagrant
|
||||
*.log
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
<?php
|
||||
|
||||
use PhpCsFixer\Config;
|
||||
use PhpCsFixer\Finder;
|
||||
|
||||
$finder = (new Finder())
|
||||
->in(__DIR__)
|
||||
->exclude([
|
||||
'vendor',
|
||||
'node_modules',
|
||||
'storage',
|
||||
'bootstrap/cache',
|
||||
])
|
||||
->notName(['_ide_helper*']);
|
||||
|
||||
return (new Config())
|
||||
->setRiskyAllowed(true)
|
||||
->setFinder($finder)
|
||||
->setRules([
|
||||
'@Symfony' => true,
|
||||
'@PSR1' => true,
|
||||
'@PSR2' => true,
|
||||
'@PSR12' => true,
|
||||
'align_multiline_comment' => ['comment_type' => 'phpdocs_like'],
|
||||
'combine_consecutive_unsets' => true,
|
||||
'concat_space' => ['spacing' => 'one'],
|
||||
'heredoc_to_nowdoc' => true,
|
||||
'no_alias_functions' => true,
|
||||
'no_unreachable_default_argument_value' => true,
|
||||
'no_useless_return' => true,
|
||||
'ordered_imports' => [
|
||||
'sort_algorithm' => 'length',
|
||||
],
|
||||
'phpdoc_align' => [
|
||||
'align' => 'left',
|
||||
'tags' => [
|
||||
'param',
|
||||
'property',
|
||||
'return',
|
||||
'throws',
|
||||
'type',
|
||||
'var',
|
||||
],
|
||||
],
|
||||
'random_api_migration' => true,
|
||||
'ternary_to_null_coalescing' => true,
|
||||
'yoda_style' => [
|
||||
'equal' => false,
|
||||
'identical' => false,
|
||||
'less_and_greater' => false,
|
||||
],
|
||||
]);
|
||||
55
.php_cs
Normal file
55
.php_cs
Normal file
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
$finder = PhpCsFixer\Finder::create()
|
||||
->in([
|
||||
'app',
|
||||
'bootstrap',
|
||||
'config',
|
||||
'database',
|
||||
'resources/lang',
|
||||
'routes',
|
||||
'tests',
|
||||
]);
|
||||
|
||||
return PhpCsFixer\Config::create()
|
||||
->setRules([
|
||||
'@Symfony' => true,
|
||||
'@PSR1' => true,
|
||||
'@PSR2' => true,
|
||||
'align_multiline_comment' => ['comment_type' => 'phpdocs_like'],
|
||||
'array_syntax' => ['syntax' => 'short'],
|
||||
'blank_line_before_return' => true,
|
||||
'blank_line_before_statement' => false,
|
||||
'combine_consecutive_unsets' => true,
|
||||
'concat_space' => ['spacing' => 'one'],
|
||||
'declare_equal_normalize' => ['space' => 'single'],
|
||||
'heredoc_to_nowdoc' => true,
|
||||
'increment_style' => ['style' => 'post'],
|
||||
'linebreak_after_opening_tag' => true,
|
||||
'method_argument_space' => [
|
||||
'ensure_fully_multiline' => false,
|
||||
'keep_multiple_spaces_after_comma' => false,
|
||||
],
|
||||
'new_with_braces' => false,
|
||||
'no_alias_functions' => true,
|
||||
'no_multiline_whitespace_before_semicolons' => true,
|
||||
'no_unreachable_default_argument_value' => true,
|
||||
'no_useless_return' => true,
|
||||
'not_operator_with_successor_space' => true,
|
||||
'ordered_imports' => [
|
||||
'sortAlgorithm' => 'length',
|
||||
],
|
||||
'phpdoc_align' => ['tags' => ['param']],
|
||||
'phpdoc_separation' => false,
|
||||
'protected_to_private' => false,
|
||||
'psr0' => ['dir' => 'app'],
|
||||
'psr4' => true,
|
||||
'random_api_migration' => true,
|
||||
'standardize_not_equals' => true,
|
||||
'ternary_to_null_coalescing' => true,
|
||||
'yoda_style' => [
|
||||
'equal' => false,
|
||||
'identical' => false,
|
||||
'less_and_greater' => false,
|
||||
],
|
||||
])->setRiskyAllowed(true)->setFinder($finder);
|
||||
@@ -1,9 +0,0 @@
|
||||
{
|
||||
"printWidth": 120,
|
||||
"tabWidth": 4,
|
||||
"useTabs": false,
|
||||
"semi": true,
|
||||
"singleQuote": true,
|
||||
"jsxSingleQuote": true,
|
||||
"endOfLine": "lf"
|
||||
}
|
||||
16
.sami.php
Normal file
16
.sami.php
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
use Sami\Sami;
|
||||
use Symfony\Component\Finder\Finder;
|
||||
|
||||
$iterator = Finder::create()
|
||||
->files()
|
||||
->name('*.php')
|
||||
->in($dir = __DIR__ . '/app');
|
||||
|
||||
return new Sami($iterator, array(
|
||||
'title' => 'Pterodactyl',
|
||||
'build_dir' => __DIR__ . '/.sami/build',
|
||||
'cache_dir' => __DIR__ . '/.sami/cache',
|
||||
'default_opened_level' => 2,
|
||||
));
|
||||
7
.styleci.yml
Normal file
7
.styleci.yml
Normal file
@@ -0,0 +1,7 @@
|
||||
preset: laravel
|
||||
risky: false
|
||||
disabled:
|
||||
- concat_without_spaces
|
||||
enabled:
|
||||
- concat_with_spaces
|
||||
- no_unused_imports
|
||||
44
.travis.yml
Normal file
44
.travis.yml
Normal file
@@ -0,0 +1,44 @@
|
||||
language: php
|
||||
dist: trusty
|
||||
git:
|
||||
depth: 3
|
||||
quiet: true
|
||||
matrix:
|
||||
fast_finish: true
|
||||
allow_failures:
|
||||
- env: TEST_SUITE=Coverage
|
||||
env:
|
||||
matrix:
|
||||
- TEST_SUITE=Unit
|
||||
- TEST_SUITE=Coverage
|
||||
- TEST_SUITE=Integration
|
||||
php:
|
||||
- 7.2
|
||||
sudo: false
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/.composer/cache
|
||||
services:
|
||||
- mysql
|
||||
before_install:
|
||||
- mysql -e 'CREATE DATABASE IF NOT EXISTS travis;'
|
||||
before_script:
|
||||
- echo 'opcache.enable_cli=1' >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini
|
||||
- cp .env.travis .env
|
||||
- travis_retry composer install --no-interaction --prefer-dist --no-suggest
|
||||
script:
|
||||
- if [ "$TEST_SUITE" = "Unit" ]; then vendor/bin/phpunit --bootstrap vendor/autoload.php tests/Unit; fi;
|
||||
- if [ "$TEST_SUITE" = "Coverage" ]; then vendor/bin/phpunit --bootstrap vendor/autoload.php --coverage-clover coverage.xml tests/Unit; fi;
|
||||
- if [ "$TEST_SUITE" = "Integration" ]; then vendor/bin/phpunit tests/Integration; fi;
|
||||
notifications:
|
||||
email: false
|
||||
webhooks:
|
||||
urls:
|
||||
- https://misc.schrej.net/travistodiscord/pterodev.php
|
||||
on_success: change
|
||||
on_failure: always
|
||||
on_error: always
|
||||
on_cancel: always
|
||||
on_start: never
|
||||
after_success:
|
||||
- bash <(curl -s https://codecov.io/bash)
|
||||
1108
CHANGELOG.md
Normal file
1108
CHANGELOG.md
Normal file
File diff suppressed because it is too large
Load Diff
74
CODE_OF_CONDUCT.md
Normal file
74
CODE_OF_CONDUCT.md
Normal file
@@ -0,0 +1,74 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as
|
||||
contributors and maintainers pledge to making participation in our project and
|
||||
our community a harassment-free experience for everyone, regardless of age, body
|
||||
size, disability, ethnicity, gender identity and expression, level of experience,
|
||||
nationality, personal appearance, race, religion, or sexual identity and
|
||||
orientation.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment
|
||||
include:
|
||||
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery and unwelcome sexual attention or
|
||||
advances
|
||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or electronic
|
||||
address, without explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of acceptable
|
||||
behavior and are expected to take appropriate and fair corrective action in
|
||||
response to any instances of unacceptable behavior.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or
|
||||
reject comments, commits, code, wiki edits, issues, and other contributions
|
||||
that are not aligned to this Code of Conduct, or to ban temporarily or
|
||||
permanently any contributor for other behaviors that they deem inappropriate,
|
||||
threatening, offensive, or harmful.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public spaces
|
||||
when an individual is representing the project or its community. Examples of
|
||||
representing a project or community include using an official project e-mail
|
||||
address, posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event. Representation of a project may be
|
||||
further defined and clarified by project maintainers.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported by contacting the project team at support@pterodactyl.io. All
|
||||
complaints will be reviewed and investigated and will result in a response that
|
||||
is deemed necessary and appropriate to the circumstances. The project team is
|
||||
obligated to maintain confidentiality with regard to the reporter of an incident.
|
||||
Further details of specific enforcement policies may be posted separately.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good
|
||||
faith may face temporary or permanent repercussions as determined by other
|
||||
members of the project's leadership.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
||||
available at [http://contributor-covenant.org/version/1/4][version]
|
||||
|
||||
[homepage]: http://contributor-covenant.org
|
||||
[version]: http://contributor-covenant.org/version/1/4/
|
||||
44
CONTRIBUTING.md
Normal file
44
CONTRIBUTING.md
Normal file
@@ -0,0 +1,44 @@
|
||||
# Contributing
|
||||
We're glad you want to help us out and make this panel the best that it can be! We have a few simple things to follow when making changes to files and adding new features.
|
||||
|
||||
### Project Branches
|
||||
This section mainly applies to those with read/write access to our repositories, but can be helpful for others.
|
||||
|
||||
The `develop` branch should always be in a runnable state, and not contain any major breaking features. For the most part, this means you will need to create `feature/` branches in order to add new functionality or change how things work. When making a feature branch, if it is referencing something in the issue tracker, please title the branch `feature/PTDL-###` where `###` is the issue number.
|
||||
|
||||
Moving forward all commits from contributors should be in the form of a PR, unless it is something we have previously discussed as being able to be pushed right into `develop`.
|
||||
|
||||
All new code should contain unit tests at a minimum (where applicable). There is a lot of uncovered code currently, so as you are doing things please be looking for places that you can write tests.
|
||||
|
||||
### Update the CHANGELOG
|
||||
When adding something that is new, fixed, changed, or security-related for the next release you should be adding a note to the CHANGELOG. If something is changing within the same version (i.e. fixing a bug introduced but not released) it should _not_ go into the CHANGELOG.
|
||||
|
||||
### Code Guidelines
|
||||
We are a `PSR-4` and `PSR-0` compliant project, so please follow those guidelines at a minimum. In addition, StyleCI runs on all of our code to ensure the formatting is standardized across everything. When a PR is made StyleCI will analyze your code and make a pull to that branch if necessary to fix any formatting issues. This project also ships with a PHP-CS configuration file and you are welcome to configure your local environment to make use of that.
|
||||
|
||||
All class variable declarations should be in alphabetical order, and constructor arguments should be in alphabetical order based on the classname. See the example below for how this should look, or check out any of the `app/Service` files for examples.
|
||||
|
||||
```php
|
||||
class ProcessScheduleService
|
||||
{
|
||||
protected $repository;
|
||||
protected $runnerService;
|
||||
|
||||
public function __construct(RunTaskService $runnerService, ScheduleRepositoryInterface $repository)
|
||||
{
|
||||
$this->repository = $repository;
|
||||
$this->runnerService = $runnerService;
|
||||
}
|
||||
```
|
||||
|
||||
### Responsible Disclosure
|
||||
This is a fairly in-depth project and makes use of a lot of parts. We strive to keep everything as secure as possible and welcome you to take a look at the code provided in this project yourself. We do ask that you be considerate of others who are using the software and not publicly disclose security issues without contacting us first by email.
|
||||
|
||||
We'll make a deal with you: if you contact us by email and we fail to respond to you within a week you are welcome to publicly disclose whatever issue you have found. We understand how frustrating it is when you find something big and no one will respond to you. This holds us to a standard of providing prompt attention to any issues that arise and keeping this community safe.
|
||||
|
||||
If you've found what you believe is a security issue please email us at `support@pterodactyl.io`.
|
||||
|
||||
### Where to find Us
|
||||
You can find us in a couple places online. First and foremost, we're active right here on Github. If you encounter a bug or other problems, open an issue on here for us to take a look at it. We also accept feature requests here as well.
|
||||
|
||||
You can also find us on [Discord](https://pterodactyl.io/discord). In the event that you need to get in contact with us privately feel free to contact us at `support@pterodactyl.io`. Try not to email us with requests for support regarding the panel, we'll probably just direct you to our Discord.
|
||||
14
CONTRIBUTORS.md
Normal file
14
CONTRIBUTORS.md
Normal file
@@ -0,0 +1,14 @@
|
||||
# Pterodactyl Panel Contributors
|
||||
This panel would not be possible without the support of our wonderful community of
|
||||
developers who provide code enhancements, new features, and bug fixes to make this panel
|
||||
the best that is can be. You can view a full listing of contributors [here](https://github.com/Pterodactyl/Panel/graphs/contributors).
|
||||
|
||||
Dane Everitt [@DaneEveritt](https://github.com/Pterodactyl/Panel/commits?author=DaneEveritt)
|
||||
|
||||
Dylan Seidt [@DDynamic](https://github.com/Pterodactyl/Panel/commits?author=DDynamic)
|
||||
|
||||
[@nikkiii](https://github.com/Pterodactyl/Panel/commits?author=nikkiii)
|
||||
|
||||
# Get Involved
|
||||
See our `CONTRIBUTING.md` document for information on how to get started. Once you've submitted some code feel free to
|
||||
modify this file and add your name to the list. Please follow the format above for your name and linking to your contributions.
|
||||
12
Caddyfile
12
Caddyfile
@@ -1,12 +0,0 @@
|
||||
{
|
||||
admin off
|
||||
email {$ADMIN_EMAIL}
|
||||
}
|
||||
|
||||
{$APP_URL} {
|
||||
root * /var/www/html/public
|
||||
encode gzip
|
||||
|
||||
php_fastcgi 127.0.0.1:9000
|
||||
file_server
|
||||
}
|
||||
64
Dockerfile
64
Dockerfile
@@ -1,58 +1,26 @@
|
||||
# Pelican Production Dockerfile
|
||||
FROM alpine:3.8
|
||||
|
||||
FROM node:20-alpine AS yarn
|
||||
#FROM --platform=$TARGETOS/$TARGETARCH node:20-alpine AS yarn
|
||||
WORKDIR /app
|
||||
|
||||
WORKDIR /build
|
||||
RUN apk add --no-cache --update ca-certificates certbot nginx dcron curl tini php7 php7-bcmath php7-common php7-dom php7-fpm php7-gd php7-mbstring php7-openssl php7-zip php7-pdo php7-phar php7-json php7-pdo_mysql php7-session php7-ctype php7-tokenizer php7-zlib php7-simplexml php7-fileinfo supervisor \
|
||||
&& curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
|
||||
|
||||
COPY . ./
|
||||
|
||||
RUN yarn config set network-timeout 300000 \
|
||||
&& yarn install --frozen-lockfile \
|
||||
&& yarn run build:production
|
||||
RUN cp .env.example .env \
|
||||
&& composer install --no-dev --optimize-autoloader \
|
||||
&& rm .env \
|
||||
&& chown -R nginx:nginx . && chmod -R 777 storage/* bootstrap/cache
|
||||
|
||||
FROM php:8.3-fpm-alpine
|
||||
# FROM --platform=$TARGETOS/$TARGETARCH php:8.3-fpm-alpine
|
||||
|
||||
COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer
|
||||
|
||||
WORKDIR /var/www/html
|
||||
|
||||
# Install dependencies
|
||||
RUN apk update && apk add --no-cache \
|
||||
libpng-dev libjpeg-turbo-dev freetype-dev libzip-dev icu-dev \
|
||||
zip unzip curl \
|
||||
caddy ca-certificates supervisor \
|
||||
&& docker-php-ext-install bcmath gd intl zip opcache pcntl posix pdo_mysql
|
||||
|
||||
# Copy the Caddyfile to the container
|
||||
COPY Caddyfile /etc/caddy/Caddyfile
|
||||
|
||||
# Copy the application code to the container
|
||||
COPY . .
|
||||
|
||||
COPY --from=yarn /build/public/assets ./public/assets
|
||||
|
||||
RUN touch .env
|
||||
|
||||
RUN composer install --no-dev --optimize-autoloader
|
||||
|
||||
# Set file permissions
|
||||
RUN chmod -R 755 storage bootstrap/cache
|
||||
|
||||
# Add scheduler to cron
|
||||
RUN echo "* * * * * php /var/www/html/artisan schedule:run >> /dev/null 2>&1" | crontab -u www-data -
|
||||
|
||||
## supervisord config and log dir
|
||||
RUN cp .github/docker/supervisord.conf /etc/supervisord.conf && \
|
||||
mkdir /var/log/supervisord/
|
||||
|
||||
HEALTHCHECK --interval=5m --timeout=10s --start-period=5s --retries=3 \
|
||||
CMD curl -f http://localhost/up || exit 1
|
||||
RUN cp .dev/docker/default.conf /etc/nginx/conf.d/default.conf \
|
||||
&& cp .dev/docker/www.conf /etc/php7/php-fpm.d/www.conf \
|
||||
&& cat .dev/docker/supervisord.conf > /etc/supervisord.conf \
|
||||
&& echo "* * * * * /usr/bin/php /app/artisan schedule:run >> /dev/null 2>&1" >> /var/spool/cron/crontabs/root \
|
||||
&& sed -i s/ssl_session_cache/#ssl_session_cache/g /etc/nginx/nginx.conf \
|
||||
&& mkdir -p /var/run/php /var/run/nginx
|
||||
|
||||
EXPOSE 80 443
|
||||
|
||||
VOLUME /pelican-data
|
||||
ENTRYPOINT ["/bin/ash", ".dev/docker/entrypoint.sh"]
|
||||
|
||||
ENTRYPOINT [ "/bin/ash", ".github/docker/entrypoint.sh" ]
|
||||
CMD [ "supervisord", "-n", "-c", "/etc/supervisord.conf" ]
|
||||
CMD [ "supervisord", "-n", "-c", "/etc/supervisord.conf" ]
|
||||
23
LICENSE.md
Normal file
23
LICENSE.md
Normal file
@@ -0,0 +1,23 @@
|
||||
# The MIT License (MIT)
|
||||
|
||||
```
|
||||
Copyright (c) 2015 - 2020 Dane Everitt <dane@daneeveritt.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
```
|
||||
75
README.md
Normal file
75
README.md
Normal file
@@ -0,0 +1,75 @@
|
||||
[](https://pterodactyl.io)
|
||||
|
||||
[](https://travis-ci.org/pterodactyl/panel)
|
||||
[](https://styleci.io/repos/47508644)
|
||||
[](https://codecov.io/gh/Pterodactyl/Panel)
|
||||
[](https://pterodactyl.io/discord)
|
||||
|
||||
# Pterodactyl Panel
|
||||
|
||||
Pterodactyl is the open-source game server management panel built with PHP7, Nodejs, and Go. Designed with security in mind, Pterodactyl runs all game servers in isolated Docker containers while exposing a beautiful and intuitive UI to administrators and users.
|
||||
What more are you waiting for? Make game servers a first class citizen on your platform today.
|
||||
|
||||

|
||||
|
||||
## Support & Documentation
|
||||
Support for using Pterodactyl can be found on our [Documentation Website](https://pterodactyl.io/project/introduction.html), [Guides Website](https://guides.pterodactyl.io), or via our [Discord Chat](https://discord.gg/QRDZvVm).
|
||||
|
||||
### Supported Games
|
||||
We support a huge variety of games by utilizing Docker containers to isolate each instance, giving you the power to host your games across the world without having to bloat each physical machine with additional dependencies.
|
||||
|
||||
Some of our core supported games include:
|
||||
|
||||
* Minecraft — including Spigot, Sponge, Bungeecord, Waterfall, and more
|
||||
* Rust
|
||||
* Terraria
|
||||
* Teamspeak
|
||||
* Mumble
|
||||
* Team Fortress 2
|
||||
* Counter Strike: Global Offensive
|
||||
* Garry's Mod
|
||||
* ARK: Survival Evolved
|
||||
|
||||
In addition to our standard nest of supported games, our community is constantly pushing the limits of this software and there are plenty more games available provided by the community. Some of these games include:
|
||||
|
||||
* Factorio
|
||||
* San Andreas: MP
|
||||
* Pocketmine MP
|
||||
* Squad
|
||||
* FiveM
|
||||
* Xonotic
|
||||
* Discord ATLBot
|
||||
|
||||
## Credits
|
||||
This software would not be possible without the work of other open-source authors who provide tools such as:
|
||||
|
||||
[Ace Editor](https://ace.c9.io), [AdminLTE](https://almsaeedstudio.com), [Animate.css](http://daneden.github.io/animate.css/), [AnsiUp](https://github.com/drudru/ansi_up), [Async.js](https://github.com/caolan/async),
|
||||
[Bootstrap](http://getbootstrap.com), [Bootstrap Notify](http://bootstrap-notify.remabledesigns.com), [Chart.js](http://www.chartjs.org), [FontAwesome](http://fontawesome.io),
|
||||
[FontAwesome Animations](https://github.com/l-lin/font-awesome-animation), [jQuery](http://jquery.com), [Laravel](https://laravel.com), [Lodash](https://lodash.com),
|
||||
[Select2](https://select2.github.io), [Socket.io](http://socket.io), [Socket.io File Upload](https://github.com/vote539/socketio-file-upload), [SweetAlert](http://t4t5.github.io/sweetalert),
|
||||
[Typeahead](https://github.com/bassjobsen/Bootstrap-3-Typeahead), and [Particles.js](http://vincentgarreau.com/particles.js).
|
||||
|
||||
Some Javascript and CSS used within the panel is licensed under a `MIT` or `Apache 2.0` license. Please check their respective header files for more information.
|
||||
|
||||
## License
|
||||
```
|
||||
Copyright (c) 2015 - 2018 Dane Everitt <dane@daneeveritt.com>.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
```
|
||||
17
Vagrantfile
vendored
Normal file
17
Vagrantfile
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
Vagrant.configure("2") do |config|
|
||||
config.vm.box = "bento/ubuntu-16.04"
|
||||
|
||||
config.vm.synced_folder "./", "/var/www/html/pterodactyl",
|
||||
owner: "www-data", group: "www-data"
|
||||
|
||||
config.vm.provision :shell, path: ".dev/vagrant/provision.sh"
|
||||
|
||||
config.vm.network :private_network, ip: "192.168.50.2"
|
||||
config.vm.network :forwarded_port, guest: 80, host: 50080
|
||||
config.vm.network :forwarded_port, guest: 8025, host: 58025
|
||||
config.vm.network :forwarded_port, guest: 3306, host: 53306
|
||||
|
||||
# Config for the vagrant-dns plugin (https://github.com/BerlinVagrant/vagrant-dns)
|
||||
config.dns.tld = "test"
|
||||
config.dns.patterns = [/^pterodactyl.test$/]
|
||||
end
|
||||
@@ -1,45 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Casts;
|
||||
|
||||
use App\Models\Objects\Endpoint;
|
||||
use Illuminate\Contracts\Database\Eloquent\Castable;
|
||||
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
class EndpointCollection implements Castable
|
||||
{
|
||||
public static function castUsing(array $arguments)
|
||||
{
|
||||
return new class() implements CastsAttributes
|
||||
{
|
||||
public function get($model, $key, $value, $attributes)
|
||||
{
|
||||
if (!isset($attributes[$key])) {
|
||||
return new Collection();
|
||||
}
|
||||
|
||||
$data = json_decode($attributes[$key], true);
|
||||
|
||||
return (new Collection($data))->map(function ($value) {
|
||||
return new Endpoint($value);
|
||||
});
|
||||
}
|
||||
|
||||
public function set($model, $key, $value, $attributes)
|
||||
{
|
||||
if (!is_array($value) && !$value instanceof Collection) {
|
||||
return new Collection();
|
||||
}
|
||||
|
||||
if (!$value instanceof Collection) {
|
||||
$value = new Collection($value);
|
||||
}
|
||||
|
||||
return [
|
||||
'ports' => $value->toJson(),
|
||||
];
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands\Egg;
|
||||
|
||||
use App\Models\Egg;
|
||||
use App\Services\Eggs\Sharing\EggExporterService;
|
||||
use Exception;
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
class CheckEggUpdatesCommand extends Command
|
||||
{
|
||||
protected $signature = 'p:egg:check-updates';
|
||||
|
||||
public function handle(EggExporterService $exporterService): void
|
||||
{
|
||||
$eggs = Egg::all();
|
||||
foreach ($eggs as $egg) {
|
||||
try {
|
||||
if (is_null($egg->update_url)) {
|
||||
$this->comment("{$egg->name}: Skipping (no update url set)");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$currentJson = json_decode($exporterService->handle($egg->id));
|
||||
unset($currentJson->exported_at);
|
||||
|
||||
$updatedJson = json_decode(file_get_contents($egg->update_url));
|
||||
unset($updatedJson->exported_at);
|
||||
|
||||
if (md5(json_encode($currentJson)) === md5(json_encode($updatedJson))) {
|
||||
$this->info("{$egg->name}: Up-to-date");
|
||||
cache()->put("eggs.{$egg->uuid}.update", false, now()->addHour());
|
||||
} else {
|
||||
$this->warn("{$egg->name}: Found update");
|
||||
cache()->put("eggs.{$egg->uuid}.update", true, now()->addHour());
|
||||
}
|
||||
} catch (Exception $exception) {
|
||||
$this->error("{$egg->name}: Error ({$exception->getMessage()})");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,29 +1,193 @@
|
||||
<?php
|
||||
/**
|
||||
* Pterodactyl - Panel
|
||||
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
|
||||
*
|
||||
* This software is licensed under the terms of the MIT license.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
namespace App\Console\Commands\Environment;
|
||||
namespace Pterodactyl\Console\Commands\Environment;
|
||||
|
||||
use DateTimeZone;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\Artisan;
|
||||
use Illuminate\Contracts\Console\Kernel;
|
||||
use Pterodactyl\Traits\Commands\EnvironmentWriterTrait;
|
||||
use Illuminate\Contracts\Config\Repository as ConfigRepository;
|
||||
|
||||
class AppSettingsCommand extends Command
|
||||
{
|
||||
use EnvironmentWriterTrait;
|
||||
|
||||
const ALLOWED_CACHE_DRIVERS = [
|
||||
'redis' => 'Redis (recommended)',
|
||||
'memcached' => 'Memcached',
|
||||
'file' => 'Filesystem',
|
||||
];
|
||||
|
||||
const ALLOWED_SESSION_DRIVERS = [
|
||||
'redis' => 'Redis (recommended)',
|
||||
'memcached' => 'Memcached',
|
||||
'database' => 'MySQL Database',
|
||||
'file' => 'Filesystem',
|
||||
'cookie' => 'Cookie',
|
||||
];
|
||||
|
||||
const ALLOWED_QUEUE_DRIVERS = [
|
||||
'redis' => 'Redis (recommended)',
|
||||
'database' => 'MySQL Database',
|
||||
'sync' => 'Sync',
|
||||
];
|
||||
|
||||
/**
|
||||
* @var \Illuminate\Contracts\Console\Kernel
|
||||
*/
|
||||
protected $command;
|
||||
|
||||
/**
|
||||
* @var \Illuminate\Contracts\Config\Repository
|
||||
*/
|
||||
protected $config;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Configure basic environment settings for the Panel.';
|
||||
|
||||
protected $signature = 'p:environment:setup';
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'p:environment:setup
|
||||
{--new-salt : Whether or not to generate a new salt for Hashids.}
|
||||
{--author= : The email that services created on this instance should be linked to.}
|
||||
{--url= : The URL that this Panel is running on.}
|
||||
{--timezone= : The timezone to use for Panel times.}
|
||||
{--cache= : The cache driver backend to use.}
|
||||
{--session= : The session driver backend to use.}
|
||||
{--queue= : The queue driver backend to use.}
|
||||
{--redis-host= : Redis host to use for connections.}
|
||||
{--redis-pass= : Password used to connect to redis.}
|
||||
{--redis-port= : Port to connect to redis over.}
|
||||
{--disable-settings-ui}';
|
||||
|
||||
public function handle(): void
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $variables = [];
|
||||
|
||||
/**
|
||||
* AppSettingsCommand constructor.
|
||||
*
|
||||
* @param \Illuminate\Contracts\Config\Repository $config
|
||||
* @param \Illuminate\Contracts\Console\Kernel $command
|
||||
*/
|
||||
public function __construct(ConfigRepository $config, Kernel $command)
|
||||
{
|
||||
$path = base_path('.env');
|
||||
if (!file_exists($path)) {
|
||||
$this->comment('Copying example .env file');
|
||||
copy($path . '.example', $path);
|
||||
parent::__construct();
|
||||
|
||||
$this->command = $command;
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle command execution.
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\PterodactylException
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
if (empty($this->config->get('hashids.salt')) || $this->option('new-salt')) {
|
||||
$this->variables['HASHIDS_SALT'] = str_random(20);
|
||||
}
|
||||
|
||||
if (!config('app.key')) {
|
||||
$this->comment('Generating app key');
|
||||
Artisan::call('key:generate');
|
||||
$this->output->comment(trans('command/messages.environment.app.author_help'));
|
||||
$this->variables['APP_SERVICE_AUTHOR'] = $this->option('author') ?? $this->ask(
|
||||
trans('command/messages.environment.app.author'), $this->config->get('pterodactyl.service.author', 'unknown@unknown.com')
|
||||
);
|
||||
|
||||
$this->output->comment(trans('command/messages.environment.app.app_url_help'));
|
||||
$this->variables['APP_URL'] = $this->option('url') ?? $this->ask(
|
||||
trans('command/messages.environment.app.app_url'), $this->config->get('app.url', 'http://example.org')
|
||||
);
|
||||
|
||||
$this->output->comment(trans('command/messages.environment.app.timezone_help'));
|
||||
$this->variables['APP_TIMEZONE'] = $this->option('timezone') ?? $this->anticipate(
|
||||
trans('command/messages.environment.app.timezone'),
|
||||
DateTimeZone::listIdentifiers(DateTimeZone::ALL),
|
||||
$this->config->get('app.timezone')
|
||||
);
|
||||
|
||||
$selected = $this->config->get('cache.default', 'redis');
|
||||
$this->variables['CACHE_DRIVER'] = $this->option('cache') ?? $this->choice(
|
||||
trans('command/messages.environment.app.cache_driver'),
|
||||
self::ALLOWED_CACHE_DRIVERS,
|
||||
array_key_exists($selected, self::ALLOWED_CACHE_DRIVERS) ? $selected : null
|
||||
);
|
||||
|
||||
$selected = $this->config->get('session.driver', 'redis');
|
||||
$this->variables['SESSION_DRIVER'] = $this->option('session') ?? $this->choice(
|
||||
trans('command/messages.environment.app.session_driver'),
|
||||
self::ALLOWED_SESSION_DRIVERS,
|
||||
array_key_exists($selected, self::ALLOWED_SESSION_DRIVERS) ? $selected : null
|
||||
);
|
||||
|
||||
$selected = $this->config->get('queue.default', 'redis');
|
||||
$this->variables['QUEUE_CONNECTION'] = $this->option('queue') ?? $this->choice(
|
||||
trans('command/messages.environment.app.queue_driver'),
|
||||
self::ALLOWED_QUEUE_DRIVERS,
|
||||
array_key_exists($selected, self::ALLOWED_QUEUE_DRIVERS) ? $selected : null
|
||||
);
|
||||
|
||||
if ($this->option('disable-settings-ui')) {
|
||||
$this->variables['APP_ENVIRONMENT_ONLY'] = 'true';
|
||||
} else {
|
||||
$this->variables['APP_ENVIRONMENT_ONLY'] = $this->confirm(trans('command/messages.environment.app.settings'), true) ? 'false' : 'true';
|
||||
}
|
||||
|
||||
Artisan::call('filament:optimize');
|
||||
$this->checkForRedis();
|
||||
$this->writeToEnvironment($this->variables);
|
||||
|
||||
$this->info($this->command->output());
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if redis is selected, if so, request connection details and verify them.
|
||||
*/
|
||||
private function checkForRedis()
|
||||
{
|
||||
$items = collect($this->variables)->filter(function ($item) {
|
||||
return $item === 'redis';
|
||||
});
|
||||
|
||||
// Redis was not selected, no need to continue.
|
||||
if (count($items) === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->output->note(trans('command/messages.environment.app.using_redis'));
|
||||
$this->variables['REDIS_HOST'] = $this->option('redis-host') ?? $this->ask(
|
||||
trans('command/messages.environment.app.redis_host'), $this->config->get('database.redis.default.host')
|
||||
);
|
||||
|
||||
$askForRedisPassword = true;
|
||||
if (! empty($this->config->get('database.redis.default.password'))) {
|
||||
$this->variables['REDIS_PASSWORD'] = $this->config->get('database.redis.default.password');
|
||||
$askForRedisPassword = $this->confirm(trans('command/messages.environment.app.redis_pass_defined'));
|
||||
}
|
||||
|
||||
if ($askForRedisPassword) {
|
||||
$this->output->comment(trans('command/messages.environment.app.redis_pass_help'));
|
||||
$this->variables['REDIS_PASSWORD'] = $this->option('redis-pass') ?? $this->output->askHidden(
|
||||
trans('command/messages.environment.app.redis_password')
|
||||
);
|
||||
}
|
||||
|
||||
if (empty($this->variables['REDIS_PASSWORD'])) {
|
||||
$this->variables['REDIS_PASSWORD'] = 'null';
|
||||
}
|
||||
|
||||
$this->variables['REDIS_PORT'] = $this->option('redis-port') ?? $this->ask(
|
||||
trans('command/messages.environment.app.redis_port'), $this->config->get('database.redis.default.port')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands\Environment;
|
||||
|
||||
use App\Traits\Commands\RequestRedisSettingsTrait;
|
||||
use App\Traits\EnvironmentWriterTrait;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Contracts\Console\Kernel;
|
||||
|
||||
class CacheSettingsCommand extends Command
|
||||
{
|
||||
use EnvironmentWriterTrait;
|
||||
use RequestRedisSettingsTrait;
|
||||
|
||||
public const CACHE_DRIVERS = [
|
||||
'file' => 'Filesystem (default)',
|
||||
'database' => 'Database',
|
||||
'redis' => 'Redis',
|
||||
];
|
||||
|
||||
protected $description = 'Configure cache settings for the Panel.';
|
||||
|
||||
protected $signature = 'p:environment:cache
|
||||
{--driver= : The cache driver backend to use.}
|
||||
{--redis-host= : Redis host to use for connections.}
|
||||
{--redis-user= : User used to connect to redis.}
|
||||
{--redis-pass= : Password used to connect to redis.}
|
||||
{--redis-port= : Port to connect to redis over.}';
|
||||
|
||||
protected array $variables = [];
|
||||
|
||||
/**
|
||||
* CacheSettingsCommand constructor.
|
||||
*/
|
||||
public function __construct(private Kernel $console)
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle command execution.
|
||||
*/
|
||||
public function handle(): int
|
||||
{
|
||||
$selected = config('cache.default', 'file');
|
||||
$this->variables['CACHE_STORE'] = $this->option('driver') ?? $this->choice(
|
||||
'Cache Driver',
|
||||
self::CACHE_DRIVERS,
|
||||
array_key_exists($selected, self::CACHE_DRIVERS) ? $selected : null
|
||||
);
|
||||
|
||||
if ($this->variables['CACHE_STORE'] === 'redis') {
|
||||
$this->requestRedisSettings();
|
||||
|
||||
if (config('queue.default') !== 'sync') {
|
||||
$this->call('p:environment:queue-service', [
|
||||
'--overwrite' => true,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
$this->writeToEnvironment($this->variables);
|
||||
|
||||
$this->info($this->console->output());
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -1,186 +1,126 @@
|
||||
<?php
|
||||
/**
|
||||
* Pterodactyl - Panel
|
||||
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
|
||||
*
|
||||
* This software is licensed under the terms of the MIT license.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
namespace App\Console\Commands\Environment;
|
||||
namespace Pterodactyl\Console\Commands\Environment;
|
||||
|
||||
use App\Traits\EnvironmentWriterTrait;
|
||||
use PDOException;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Contracts\Console\Kernel;
|
||||
use Illuminate\Database\DatabaseManager;
|
||||
use Pterodactyl\Traits\Commands\EnvironmentWriterTrait;
|
||||
use Illuminate\Contracts\Config\Repository as ConfigRepository;
|
||||
|
||||
class DatabaseSettingsCommand extends Command
|
||||
{
|
||||
use EnvironmentWriterTrait;
|
||||
|
||||
public const DATABASE_DRIVERS = [
|
||||
'sqlite' => 'SQLite (recommended)',
|
||||
'mariadb' => 'MariaDB',
|
||||
'mysql' => 'MySQL',
|
||||
];
|
||||
/**
|
||||
* @var \Illuminate\Contracts\Config\Repository
|
||||
*/
|
||||
protected $config;
|
||||
|
||||
/**
|
||||
* @var \Illuminate\Contracts\Console\Kernel
|
||||
*/
|
||||
protected $console;
|
||||
|
||||
/**
|
||||
* @var \Illuminate\Database\DatabaseManager
|
||||
*/
|
||||
protected $database;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Configure database settings for the Panel.';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'p:environment:database
|
||||
{--driver= : The database driver backend to use.}
|
||||
{--host= : The connection address for the MySQL server.}
|
||||
{--port= : The connection port for the MySQL server.}
|
||||
{--database= : The database to use.}
|
||||
{--host= : The connection address for the MySQL/ MariaDB server.}
|
||||
{--port= : The connection port for the MySQL/ MariaDB server.}
|
||||
{--username= : Username to use when connecting to the MySQL/ MariaDB server.}
|
||||
{--password= : Password to use for the MySQL/ MariaDB database.}';
|
||||
{--username= : Username to use when connecting.}
|
||||
{--password= : Password to use for this database.}';
|
||||
|
||||
protected array $variables = [];
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $variables = [];
|
||||
|
||||
/**
|
||||
* DatabaseSettingsCommand constructor.
|
||||
*
|
||||
* @param \Illuminate\Contracts\Config\Repository $config
|
||||
* @param \Illuminate\Database\DatabaseManager $database
|
||||
* @param \Illuminate\Contracts\Console\Kernel $console
|
||||
*/
|
||||
public function __construct(private DatabaseManager $database, private Kernel $console)
|
||||
public function __construct(ConfigRepository $config, DatabaseManager $database, Kernel $console)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->config = $config;
|
||||
$this->console = $console;
|
||||
$this->database = $database;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle command execution.
|
||||
*
|
||||
* @return int
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\PterodactylException
|
||||
*/
|
||||
public function handle(): int
|
||||
public function handle()
|
||||
{
|
||||
$this->error('Changing the database driver will NOT move any database data!');
|
||||
$this->error('Please make sure you made a database backup first!');
|
||||
$this->error('After changing the driver you will have to manually move the old data to the new database.');
|
||||
if (!$this->confirm('Do you want to continue?')) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
$selected = config('database.default', 'sqlite');
|
||||
$this->variables['DB_CONNECTION'] = $this->option('driver') ?? $this->choice(
|
||||
'Database Driver',
|
||||
self::DATABASE_DRIVERS,
|
||||
array_key_exists($selected, self::DATABASE_DRIVERS) ? $selected : null
|
||||
$this->output->note(trans('command/messages.environment.database.host_warning'));
|
||||
$this->variables['DB_HOST'] = $this->option('host') ?? $this->ask(
|
||||
trans('command/messages.environment.database.host'), $this->config->get('database.connections.mysql.host', '127.0.0.1')
|
||||
);
|
||||
|
||||
if ($this->variables['DB_CONNECTION'] === 'mysql') {
|
||||
$this->output->note(__('commands.database_settings.DB_HOST_note'));
|
||||
$this->variables['DB_HOST'] = $this->option('host') ?? $this->ask(
|
||||
'Database Host',
|
||||
config('database.connections.mysql.host', '127.0.0.1')
|
||||
);
|
||||
$this->variables['DB_PORT'] = $this->option('port') ?? $this->ask(
|
||||
trans('command/messages.environment.database.port'), $this->config->get('database.connections.mysql.port', 3306)
|
||||
);
|
||||
|
||||
$this->variables['DB_PORT'] = $this->option('port') ?? $this->ask(
|
||||
'Database Port',
|
||||
config('database.connections.mysql.port', 3306)
|
||||
);
|
||||
$this->variables['DB_DATABASE'] = $this->option('database') ?? $this->ask(
|
||||
trans('command/messages.environment.database.database'), $this->config->get('database.connections.mysql.database', 'panel')
|
||||
);
|
||||
|
||||
$this->variables['DB_DATABASE'] = $this->option('database') ?? $this->ask(
|
||||
'Database Name',
|
||||
config('database.connections.mysql.database', 'panel')
|
||||
);
|
||||
$this->output->note(trans('command/messages.environment.database.username_warning'));
|
||||
$this->variables['DB_USERNAME'] = $this->option('username') ?? $this->ask(
|
||||
trans('command/messages.environment.database.username'), $this->config->get('database.connections.mysql.username', 'pterodactyl')
|
||||
);
|
||||
|
||||
$this->output->note(__('commands.database_settings.DB_USERNAME_note'));
|
||||
$this->variables['DB_USERNAME'] = $this->option('username') ?? $this->ask(
|
||||
'Database Username',
|
||||
config('database.connections.mysql.username', 'pelican')
|
||||
);
|
||||
$askForMySQLPassword = true;
|
||||
if (! empty($this->config->get('database.connections.mysql.password')) && $this->input->isInteractive()) {
|
||||
$this->variables['DB_PASSWORD'] = $this->config->get('database.connections.mysql.password');
|
||||
$askForMySQLPassword = $this->confirm(trans('command/messages.environment.database.password_defined'));
|
||||
}
|
||||
|
||||
$askForMySQLPassword = true;
|
||||
if (!empty(config('database.connections.mysql.password')) && $this->input->isInteractive()) {
|
||||
$this->variables['DB_PASSWORD'] = config('database.connections.mysql.password');
|
||||
$askForMySQLPassword = $this->confirm(__('commands.database_settings.DB_PASSWORD_note'));
|
||||
if ($askForMySQLPassword) {
|
||||
$this->variables['DB_PASSWORD'] = $this->option('password') ?? $this->secret(trans('command/messages.environment.database.password'));
|
||||
}
|
||||
|
||||
try {
|
||||
$this->testMySQLConnection();
|
||||
} catch (PDOException $exception) {
|
||||
$this->output->error(trans('command/messages.environment.database.connection_error', ['error' => $exception->getMessage()]));
|
||||
$this->output->error(trans('command/messages.environment.database.creds_not_saved'));
|
||||
|
||||
if ($this->confirm(trans('command/messages.environment.database.try_again'))) {
|
||||
$this->database->disconnect('_pterodactyl_command_test');
|
||||
|
||||
return $this->handle();
|
||||
}
|
||||
|
||||
if ($askForMySQLPassword) {
|
||||
$this->variables['DB_PASSWORD'] = $this->option('password') ?? $this->secret('Database Password');
|
||||
}
|
||||
|
||||
try {
|
||||
// Test connection
|
||||
config()->set('database.connections._panel_command_test', [
|
||||
'driver' => 'mysql',
|
||||
'host' => $this->variables['DB_HOST'],
|
||||
'port' => $this->variables['DB_PORT'],
|
||||
'database' => $this->variables['DB_DATABASE'],
|
||||
'username' => $this->variables['DB_USERNAME'],
|
||||
'password' => $this->variables['DB_PASSWORD'],
|
||||
'charset' => 'utf8mb4',
|
||||
'collation' => 'utf8mb4_unicode_ci',
|
||||
'strict' => true,
|
||||
]);
|
||||
|
||||
$this->database->connection('_panel_command_test')->getPdo();
|
||||
} catch (\PDOException $exception) {
|
||||
$this->output->error(sprintf('Unable to connect to the MySQL server using the provided credentials. The error returned was "%s".', $exception->getMessage()));
|
||||
$this->output->error(__('commands.database_settings.DB_error_2'));
|
||||
|
||||
if ($this->confirm(__('commands.database_settings.go_back'))) {
|
||||
$this->database->disconnect('_panel_command_test');
|
||||
|
||||
return $this->handle();
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
} elseif ($this->variables['DB_CONNECTION'] === 'mariadb') {
|
||||
$this->output->note(__('commands.database_settings.DB_HOST_note'));
|
||||
$this->variables['DB_HOST'] = $this->option('host') ?? $this->ask(
|
||||
'Database Host',
|
||||
config('database.connections.mariadb.host', '127.0.0.1')
|
||||
);
|
||||
|
||||
$this->variables['DB_PORT'] = $this->option('port') ?? $this->ask(
|
||||
'Database Port',
|
||||
config('database.connections.mariadb.port', 3306)
|
||||
);
|
||||
|
||||
$this->variables['DB_DATABASE'] = $this->option('database') ?? $this->ask(
|
||||
'Database Name',
|
||||
config('database.connections.mariadb.database', 'panel')
|
||||
);
|
||||
|
||||
$this->output->note(__('commands.database_settings.DB_USERNAME_note'));
|
||||
$this->variables['DB_USERNAME'] = $this->option('username') ?? $this->ask(
|
||||
'Database Username',
|
||||
config('database.connections.mariadb.username', 'pelican')
|
||||
);
|
||||
|
||||
$askForMariaDBPassword = true;
|
||||
if (!empty(config('database.connections.mariadb.password')) && $this->input->isInteractive()) {
|
||||
$this->variables['DB_PASSWORD'] = config('database.connections.mariadb.password');
|
||||
$askForMariaDBPassword = $this->confirm(__('commands.database_settings.DB_PASSWORD_note'));
|
||||
}
|
||||
|
||||
if ($askForMariaDBPassword) {
|
||||
$this->variables['DB_PASSWORD'] = $this->option('password') ?? $this->secret('Database Password');
|
||||
}
|
||||
|
||||
try {
|
||||
// Test connection
|
||||
config()->set('database.connections._panel_command_test', [
|
||||
'driver' => 'mariadb',
|
||||
'host' => $this->variables['DB_HOST'],
|
||||
'port' => $this->variables['DB_PORT'],
|
||||
'database' => $this->variables['DB_DATABASE'],
|
||||
'username' => $this->variables['DB_USERNAME'],
|
||||
'password' => $this->variables['DB_PASSWORD'],
|
||||
'charset' => 'utf8mb4',
|
||||
'collation' => 'utf8mb4_unicode_ci',
|
||||
'strict' => true,
|
||||
]);
|
||||
|
||||
$this->database->connection('_panel_command_test')->getPdo();
|
||||
} catch (\PDOException $exception) {
|
||||
$this->output->error(sprintf('Unable to connect to the MariaDB server using the provided credentials. The error returned was "%s".', $exception->getMessage()));
|
||||
$this->output->error(__('commands.database_settings.DB_error_2'));
|
||||
|
||||
if ($this->confirm(__('commands.database_settings.go_back'))) {
|
||||
$this->database->disconnect('_panel_command_test');
|
||||
|
||||
return $this->handle();
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
} elseif ($this->variables['DB_CONNECTION'] === 'sqlite') {
|
||||
$this->variables['DB_DATABASE'] = $this->option('database') ?? $this->ask(
|
||||
'Database Path',
|
||||
env('DB_DATABASE', 'database.sqlite')
|
||||
);
|
||||
return 1;
|
||||
}
|
||||
|
||||
$this->writeToEnvironment($this->variables);
|
||||
@@ -189,4 +129,24 @@ class DatabaseSettingsCommand extends Command
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that we can connect to the provided MySQL instance and perform a selection.
|
||||
*/
|
||||
private function testMySQLConnection()
|
||||
{
|
||||
$this->config->set('database.connections._pterodactyl_command_test', [
|
||||
'driver' => 'mysql',
|
||||
'host' => $this->variables['DB_HOST'],
|
||||
'port' => $this->variables['DB_PORT'],
|
||||
'database' => $this->variables['DB_DATABASE'],
|
||||
'username' => $this->variables['DB_USERNAME'],
|
||||
'password' => $this->variables['DB_PASSWORD'],
|
||||
'charset' => 'utf8mb4',
|
||||
'collation' => 'utf8mb4_unicode_ci',
|
||||
'strict' => true,
|
||||
]);
|
||||
|
||||
$this->database->connection('_pterodactyl_command_test')->getPdo();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,35 @@
|
||||
<?php
|
||||
/**
|
||||
* Pterodactyl - Panel
|
||||
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
|
||||
*
|
||||
* This software is licensed under the terms of the MIT license.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
namespace App\Console\Commands\Environment;
|
||||
namespace Pterodactyl\Console\Commands\Environment;
|
||||
|
||||
use App\Traits\EnvironmentWriterTrait;
|
||||
use Illuminate\Console\Command;
|
||||
use Pterodactyl\Traits\Commands\EnvironmentWriterTrait;
|
||||
use Illuminate\Contracts\Config\Repository as ConfigRepository;
|
||||
|
||||
class EmailSettingsCommand extends Command
|
||||
{
|
||||
use EnvironmentWriterTrait;
|
||||
|
||||
/**
|
||||
* @var \Illuminate\Contracts\Config\Repository
|
||||
*/
|
||||
protected $config;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Set or update the email sending configuration for the Panel.';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'p:environment:mail
|
||||
{--driver= : The mail driver to use.}
|
||||
{--email= : Email address that messages from the Panel will originate from.}
|
||||
@@ -18,51 +37,61 @@ class EmailSettingsCommand extends Command
|
||||
{--encryption=}
|
||||
{--host=}
|
||||
{--port=}
|
||||
{--endpoint=}
|
||||
{--username=}
|
||||
{--password=}';
|
||||
|
||||
protected array $variables = [];
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $variables = [];
|
||||
|
||||
/**
|
||||
* EmailSettingsCommand constructor.
|
||||
*
|
||||
* @param \Illuminate\Contracts\Config\Repository $config
|
||||
*/
|
||||
public function __construct(ConfigRepository $config)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle command execution.
|
||||
*
|
||||
* @throws \App\Exceptions\PanelException
|
||||
* @throws \Pterodactyl\Exceptions\PterodactylException
|
||||
*/
|
||||
public function handle(): void
|
||||
public function handle()
|
||||
{
|
||||
$this->variables['MAIL_MAILER'] = $this->option('driver') ?? $this->choice(
|
||||
trans('command/messages.environment.mail.ask_driver'),
|
||||
[
|
||||
'log' => 'Log',
|
||||
$this->variables['MAIL_DRIVER'] = $this->option('driver') ?? $this->choice(
|
||||
trans('command/messages.environment.mail.ask_driver'), [
|
||||
'smtp' => 'SMTP Server',
|
||||
'sendmail' => 'sendmail Binary',
|
||||
'mailgun' => 'Mailgun',
|
||||
'mandrill' => 'Mandrill',
|
||||
'postmark' => 'Postmark',
|
||||
],
|
||||
env('MAIL_MAILER', env('MAIL_DRIVER', 'smtp')),
|
||||
'mail' => 'PHP\'s Internal Mail Function',
|
||||
'mailgun' => 'Mailgun Transactional Email',
|
||||
'mandrill' => 'Mandrill Transactional Email',
|
||||
'postmark' => 'Postmarkapp Transactional Email',
|
||||
], $this->config->get('mail.driver', 'smtp')
|
||||
);
|
||||
|
||||
$method = 'setup' . studly_case($this->variables['MAIL_MAILER']) . 'DriverVariables';
|
||||
$method = 'setup' . studly_case($this->variables['MAIL_DRIVER']) . 'DriverVariables';
|
||||
if (method_exists($this, $method)) {
|
||||
$this->{$method}();
|
||||
}
|
||||
|
||||
$this->variables['MAIL_FROM_ADDRESS'] = $this->option('email') ?? $this->ask(
|
||||
trans('command/messages.environment.mail.ask_mail_from'),
|
||||
config('mail.from.address')
|
||||
$this->variables['MAIL_FROM'] = $this->option('email') ?? $this->ask(
|
||||
trans('command/messages.environment.mail.ask_mail_from'), $this->config->get('mail.from.address')
|
||||
);
|
||||
|
||||
$this->variables['MAIL_FROM_NAME'] = $this->option('from') ?? $this->ask(
|
||||
trans('command/messages.environment.mail.ask_mail_name'),
|
||||
config('mail.from.name')
|
||||
trans('command/messages.environment.mail.ask_mail_name'), $this->config->get('mail.from.name')
|
||||
);
|
||||
|
||||
$this->variables['MAIL_ENCRYPTION'] = $this->option('encryption') ?? $this->choice(
|
||||
trans('command/messages.environment.mail.ask_encryption'), ['tls' => 'TLS', 'ssl' => 'SSL', '' => 'None'], $this->config->get('mail.encryption', 'tls')
|
||||
);
|
||||
|
||||
$this->writeToEnvironment($this->variables);
|
||||
|
||||
$this->call('queue:restart');
|
||||
|
||||
$this->line('Updating stored environment configuration file.');
|
||||
$this->line('');
|
||||
}
|
||||
@@ -70,77 +99,59 @@ class EmailSettingsCommand extends Command
|
||||
/**
|
||||
* Handle variables for SMTP driver.
|
||||
*/
|
||||
private function setupSmtpDriverVariables(): void
|
||||
private function setupSmtpDriverVariables()
|
||||
{
|
||||
$this->variables['MAIL_HOST'] = $this->option('host') ?? $this->ask(
|
||||
trans('command/messages.environment.mail.ask_smtp_host'),
|
||||
config('mail.mailers.smtp.host')
|
||||
trans('command/messages.environment.mail.ask_smtp_host'), $this->config->get('mail.host')
|
||||
);
|
||||
|
||||
$this->variables['MAIL_PORT'] = $this->option('port') ?? $this->ask(
|
||||
trans('command/messages.environment.mail.ask_smtp_port'),
|
||||
config('mail.mailers.smtp.port')
|
||||
trans('command/messages.environment.mail.ask_smtp_port'), $this->config->get('mail.port')
|
||||
);
|
||||
|
||||
$this->variables['MAIL_USERNAME'] = $this->option('username') ?? $this->ask(
|
||||
trans('command/messages.environment.mail.ask_smtp_username'),
|
||||
config('mail.mailers.smtp.username')
|
||||
trans('command/messages.environment.mail.ask_smtp_username'), $this->config->get('mail.username')
|
||||
);
|
||||
|
||||
$this->variables['MAIL_PASSWORD'] = $this->option('password') ?? $this->secret(
|
||||
trans('command/messages.environment.mail.ask_smtp_password')
|
||||
);
|
||||
|
||||
$this->variables['MAIL_ENCRYPTION'] = $this->option('encryption') ?? $this->choice(
|
||||
trans('command/messages.environment.mail.ask_encryption'),
|
||||
['tls' => 'TLS', 'ssl' => 'SSL', '' => 'None'],
|
||||
config('mail.mailers.smtp.encryption', 'tls')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle variables for mailgun driver.
|
||||
*/
|
||||
private function setupMailgunDriverVariables(): void
|
||||
private function setupMailgunDriverVariables()
|
||||
{
|
||||
$this->variables['MAILGUN_DOMAIN'] = $this->option('host') ?? $this->ask(
|
||||
trans('command/messages.environment.mail.ask_mailgun_domain'),
|
||||
config('services.mailgun.domain')
|
||||
trans('command/messages.environment.mail.ask_mailgun_domain'), $this->config->get('services.mailgun.domain')
|
||||
);
|
||||
|
||||
$this->variables['MAILGUN_SECRET'] = $this->option('password') ?? $this->ask(
|
||||
trans('command/messages.environment.mail.ask_mailgun_secret'),
|
||||
config('services.mailgun.secret')
|
||||
);
|
||||
|
||||
$this->variables['MAILGUN_ENDPOINT'] = $this->option('endpoint') ?? $this->ask(
|
||||
trans('command/messages.environment.mail.ask_mailgun_endpoint'),
|
||||
config('services.mailgun.endpoint')
|
||||
trans('command/messages.environment.mail.ask_mailgun_secret'), $this->config->get('services.mailgun.secret')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle variables for mandrill driver.
|
||||
*/
|
||||
private function setupMandrillDriverVariables(): void
|
||||
private function setupMandrillDriverVariables()
|
||||
{
|
||||
$this->variables['MANDRILL_SECRET'] = $this->option('password') ?? $this->ask(
|
||||
trans('command/messages.environment.mail.ask_mandrill_secret'),
|
||||
config('services.mandrill.secret')
|
||||
trans('command/messages.environment.mail.ask_mandrill_secret'), $this->config->get('services.mandrill.secret')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle variables for postmark driver.
|
||||
*/
|
||||
private function setupPostmarkDriverVariables(): void
|
||||
private function setupPostmarkDriverVariables()
|
||||
{
|
||||
$this->variables['MAIL_DRIVER'] = 'smtp';
|
||||
$this->variables['MAIL_HOST'] = 'smtp.postmarkapp.com';
|
||||
$this->variables['MAIL_PORT'] = 587;
|
||||
$this->variables['MAIL_USERNAME'] = $this->variables['MAIL_PASSWORD'] = $this->option('username') ?? $this->ask(
|
||||
trans('command/messages.environment.mail.ask_postmark_username'),
|
||||
config('mail.username')
|
||||
trans('command/messages.environment.mail.ask_postmark_username'), $this->config->get('mail.username')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands\Environment;
|
||||
|
||||
use App\Traits\Commands\RequestRedisSettingsTrait;
|
||||
use App\Traits\EnvironmentWriterTrait;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Contracts\Console\Kernel;
|
||||
|
||||
class QueueSettingsCommand extends Command
|
||||
{
|
||||
use EnvironmentWriterTrait;
|
||||
use RequestRedisSettingsTrait;
|
||||
|
||||
public const QUEUE_DRIVERS = [
|
||||
'database' => 'Database (default)',
|
||||
'redis' => 'Redis',
|
||||
'sync' => 'Synchronous',
|
||||
];
|
||||
|
||||
protected $description = 'Configure queue settings for the Panel.';
|
||||
|
||||
protected $signature = 'p:environment:queue
|
||||
{--driver= : The queue driver backend to use.}
|
||||
{--redis-host= : Redis host to use for connections.}
|
||||
{--redis-user= : User used to connect to redis.}
|
||||
{--redis-pass= : Password used to connect to redis.}
|
||||
{--redis-port= : Port to connect to redis over.}';
|
||||
|
||||
protected array $variables = [];
|
||||
|
||||
/**
|
||||
* QueueSettingsCommand constructor.
|
||||
*/
|
||||
public function __construct(private Kernel $console)
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle command execution.
|
||||
*/
|
||||
public function handle(): int
|
||||
{
|
||||
$selected = config('queue.default', 'database');
|
||||
$this->variables['QUEUE_CONNECTION'] = $this->option('driver') ?? $this->choice(
|
||||
'Queue Driver',
|
||||
self::QUEUE_DRIVERS,
|
||||
array_key_exists($selected, self::QUEUE_DRIVERS) ? $selected : null
|
||||
);
|
||||
|
||||
if ($this->variables['QUEUE_CONNECTION'] === 'redis') {
|
||||
$this->requestRedisSettings();
|
||||
|
||||
$this->call('p:environment:queue-service', [
|
||||
'--overwrite' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
$this->writeToEnvironment($this->variables);
|
||||
|
||||
$this->info($this->console->output());
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands\Environment;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\File;
|
||||
use Illuminate\Support\Facades\Process;
|
||||
|
||||
class QueueWorkerServiceCommand extends Command
|
||||
{
|
||||
protected $description = 'Create the service for the queue worker.';
|
||||
|
||||
protected $signature = 'p:environment:queue-service
|
||||
{--service-name= : Name of the queue worker service.}
|
||||
{--user= : The user that PHP runs under.}
|
||||
{--group= : The group that PHP runs under.}
|
||||
{--overwrite : Force overwrite if the service file already exists.}';
|
||||
|
||||
public function handle(): void
|
||||
{
|
||||
$serviceName = $this->option('service-name') ?? $this->ask('Queue worker service name', 'pelican-queue');
|
||||
$path = '/etc/systemd/system/' . $serviceName . '.service';
|
||||
|
||||
$fileExists = file_exists($path);
|
||||
if ($fileExists && !$this->option('overwrite') && !$this->confirm('The service file already exists. Do you want to overwrite it?')) {
|
||||
$this->line('Creation of queue worker service file aborted because service file already exists.');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$user = $this->option('user') ?? $this->ask('Webserver User', 'www-data');
|
||||
$group = $this->option('group') ?? $this->ask('Webserver Group', 'www-data');
|
||||
|
||||
$redisUsed = config('queue.default') === 'redis' || config('session.driver') === 'redis' || config('cache.default') === 'redis';
|
||||
$afterRedis = $redisUsed ? '
|
||||
After=redis-server.service' : '';
|
||||
|
||||
$basePath = base_path();
|
||||
|
||||
$success = File::put($path, "# Pelican Queue File
|
||||
# ----------------------------------
|
||||
|
||||
[Unit]
|
||||
Description=Pelican Queue Service$afterRedis
|
||||
|
||||
[Service]
|
||||
User=$user
|
||||
Group=$group
|
||||
Restart=always
|
||||
ExecStart=/usr/bin/php $basePath/artisan queue:work --tries=3
|
||||
StartLimitInterval=180
|
||||
StartLimitBurst=30
|
||||
RestartSec=5s
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
");
|
||||
|
||||
if (!$success) {
|
||||
$this->error('Error creating service file');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($fileExists) {
|
||||
$result = Process::run("systemctl restart $serviceName.service");
|
||||
if ($result->failed()) {
|
||||
$this->error('Error restarting service: ' . $result->errorOutput());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->line('Queue worker service file updated successfully.');
|
||||
} else {
|
||||
$result = Process::run("systemctl enable --now $serviceName.service");
|
||||
if ($result->failed()) {
|
||||
$this->error('Error enabling service: ' . $result->errorOutput());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->line('Queue worker service file created successfully.');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands\Environment;
|
||||
|
||||
use App\Traits\Commands\RequestRedisSettingsTrait;
|
||||
use App\Traits\EnvironmentWriterTrait;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Contracts\Console\Kernel;
|
||||
|
||||
class RedisSetupCommand extends Command
|
||||
{
|
||||
use EnvironmentWriterTrait;
|
||||
use RequestRedisSettingsTrait;
|
||||
|
||||
protected $description = 'Configure the Panel to use Redis as cache, queue and session driver.';
|
||||
|
||||
protected $signature = 'p:redis:setup
|
||||
{--redis-host= : Redis host to use for connections.}
|
||||
{--redis-user= : User used to connect to redis.}
|
||||
{--redis-pass= : Password used to connect to redis.}
|
||||
{--redis-port= : Port to connect to redis over.}';
|
||||
|
||||
protected array $variables = [];
|
||||
|
||||
/**
|
||||
* RedisSetupCommand constructor.
|
||||
*/
|
||||
public function __construct(private Kernel $console)
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle command execution.
|
||||
*/
|
||||
public function handle(): int
|
||||
{
|
||||
$this->variables['CACHE_STORE'] = 'redis';
|
||||
$this->variables['QUEUE_CONNECTION'] = 'redis';
|
||||
$this->variables['SESSION_DRIVERS'] = 'redis';
|
||||
|
||||
$this->requestRedisSettings();
|
||||
|
||||
$this->call('p:environment:queue-service', [
|
||||
'--overwrite' => true,
|
||||
]);
|
||||
|
||||
$this->writeToEnvironment($this->variables);
|
||||
|
||||
$this->info($this->console->output());
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands\Environment;
|
||||
|
||||
use App\Traits\Commands\RequestRedisSettingsTrait;
|
||||
use App\Traits\EnvironmentWriterTrait;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Contracts\Console\Kernel;
|
||||
|
||||
class SessionSettingsCommand extends Command
|
||||
{
|
||||
use EnvironmentWriterTrait;
|
||||
use RequestRedisSettingsTrait;
|
||||
|
||||
public const SESSION_DRIVERS = [
|
||||
'file' => 'Filesystem (default)',
|
||||
'redis' => 'Redis',
|
||||
'database' => 'Database',
|
||||
'cookie' => 'Cookie',
|
||||
];
|
||||
|
||||
protected $description = 'Configure session settings for the Panel.';
|
||||
|
||||
protected $signature = 'p:environment:session
|
||||
{--driver= : The session driver backend to use.}
|
||||
{--redis-host= : Redis host to use for connections.}
|
||||
{--redis-user= : User used to connect to redis.}
|
||||
{--redis-pass= : Password used to connect to redis.}
|
||||
{--redis-port= : Port to connect to redis over.}';
|
||||
|
||||
protected array $variables = [];
|
||||
|
||||
/**
|
||||
* SessionSettingsCommand constructor.
|
||||
*/
|
||||
public function __construct(private Kernel $console)
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle command execution.
|
||||
*/
|
||||
public function handle(): int
|
||||
{
|
||||
$selected = config('session.driver', 'file');
|
||||
$this->variables['SESSION_DRIVER'] = $this->option('driver') ?? $this->choice(
|
||||
'Session Driver',
|
||||
self::SESSION_DRIVERS,
|
||||
array_key_exists($selected, self::SESSION_DRIVERS) ? $selected : null
|
||||
);
|
||||
|
||||
if ($this->variables['SESSION_DRIVER'] === 'redis') {
|
||||
$this->requestRedisSettings();
|
||||
|
||||
if (config('queue.default') !== 'sync') {
|
||||
$this->call('p:environment:queue-service', [
|
||||
'--overwrite' => true,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
$this->writeToEnvironment($this->variables);
|
||||
|
||||
$this->info($this->console->output());
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -1,107 +1,112 @@
|
||||
<?php
|
||||
/**
|
||||
* Pterodactyl - Panel
|
||||
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
|
||||
*
|
||||
* This software is licensed under the terms of the MIT license.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
namespace App\Console\Commands;
|
||||
namespace Pterodactyl\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use App\Services\Helpers\SoftwareVersionService;
|
||||
use Pterodactyl\Services\Helpers\SoftwareVersionService;
|
||||
use Illuminate\Contracts\Config\Repository as ConfigRepository;
|
||||
|
||||
class InfoCommand extends Command
|
||||
{
|
||||
protected $description = 'Displays the application, database, email and backup configurations along with the panel version.';
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Displays the application, database, and email configurations along with the panel version.';
|
||||
|
||||
/**
|
||||
* @var \Illuminate\Contracts\Config\Repository
|
||||
*/
|
||||
protected $config;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'p:info';
|
||||
|
||||
/**
|
||||
* InfoCommand constructor.
|
||||
* @var \Pterodactyl\Services\Helpers\SoftwareVersionService
|
||||
*/
|
||||
public function __construct(private SoftwareVersionService $versionService)
|
||||
protected $versionService;
|
||||
|
||||
/**
|
||||
* VersionCommand constructor.
|
||||
*
|
||||
* @param \Illuminate\Contracts\Config\Repository $config
|
||||
* @param \Pterodactyl\Services\Helpers\SoftwareVersionService $versionService
|
||||
*/
|
||||
public function __construct(ConfigRepository $config, SoftwareVersionService $versionService)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->config = $config;
|
||||
$this->versionService = $versionService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle execution of command.
|
||||
*/
|
||||
public function handle(): void
|
||||
public function handle()
|
||||
{
|
||||
$this->output->title('Version Information');
|
||||
$this->table([], [
|
||||
['Panel Version', $this->versionService->versionData()['version']],
|
||||
['Panel Version', $this->config->get('app.version')],
|
||||
['Latest Version', $this->versionService->getPanel()],
|
||||
['Up-to-Date', $this->versionService->isLatestPanel() ? 'Yes' : $this->formatText('No', 'bg=red')],
|
||||
['Unique Identifier', $this->config->get('pterodactyl.service.author')],
|
||||
], 'compact');
|
||||
|
||||
$this->output->title('Application Configuration');
|
||||
$this->table([], [
|
||||
['Environment', config('app.env') === 'production' ? config('app.env') : $this->formatText(config('app.env'), 'bg=red')],
|
||||
['Debug Mode', config('app.debug') ? $this->formatText('Yes', 'bg=red') : 'No'],
|
||||
['Application Name', config('app.name')],
|
||||
['Application URL', config('app.url')],
|
||||
['Environment', $this->formatText($this->config->get('app.env'), $this->config->get('app.env') === 'production' ?: 'bg=red')],
|
||||
['Debug Mode', $this->formatText($this->config->get('app.debug') ? 'Yes' : 'No', ! $this->config->get('app.debug') ?: 'bg=red')],
|
||||
['Installation URL', $this->config->get('app.url')],
|
||||
['Installation Directory', base_path()],
|
||||
['Cache Driver', config('cache.default')],
|
||||
['Queue Driver', config('queue.default') === 'sync' ? $this->formatText(config('queue.default'), 'bg=red') : config('queue.default')],
|
||||
['Session Driver', config('session.driver')],
|
||||
['Filesystem Driver', config('filesystems.default')],
|
||||
['Timezone', $this->config->get('app.timezone')],
|
||||
['Cache Driver', $this->config->get('cache.default')],
|
||||
['Queue Driver', $this->config->get('queue.default')],
|
||||
['Session Driver', $this->config->get('session.driver')],
|
||||
['Filesystem Driver', $this->config->get('filesystems.default')],
|
||||
['Default Theme', $this->config->get('themes.active')],
|
||||
['Proxies', $this->config->get('trustedproxies.proxies')],
|
||||
], 'compact');
|
||||
|
||||
$this->output->title('Database Configuration');
|
||||
$driver = config('database.default');
|
||||
if ($driver === 'sqlite') {
|
||||
$this->table([], [
|
||||
['Driver', $driver],
|
||||
['Database', config("database.connections.$driver.database")],
|
||||
], 'compact');
|
||||
} else {
|
||||
$this->table([], [
|
||||
['Driver', $driver],
|
||||
['Host', config("database.connections.$driver.host")],
|
||||
['Port', config("database.connections.$driver.port")],
|
||||
['Database', config("database.connections.$driver.database")],
|
||||
['Username', config("database.connections.$driver.username")],
|
||||
], 'compact');
|
||||
}
|
||||
$driver = $this->config->get('database.default');
|
||||
$this->table([], [
|
||||
['Driver', $driver],
|
||||
['Host', $this->config->get("database.connections.{$driver}.host")],
|
||||
['Port', $this->config->get("database.connections.{$driver}.port")],
|
||||
['Database', $this->config->get("database.connections.{$driver}.database")],
|
||||
['Username', $this->config->get("database.connections.{$driver}.username")],
|
||||
], 'compact');
|
||||
|
||||
$this->output->title('Email Configuration');
|
||||
$driver = config('mail.default');
|
||||
if ($driver === 'smtp') {
|
||||
$this->table([], [
|
||||
['Driver', $driver],
|
||||
['Host', config("mail.mailers.$driver.host")],
|
||||
['Port', config("mail.mailers.$driver.port")],
|
||||
['Username', config("mail.mailers.$driver.username")],
|
||||
['Encryption', config("mail.mailers.$driver.encryption")],
|
||||
['From Address', config('mail.from.address')],
|
||||
['From Name', config('mail.from.name')],
|
||||
], 'compact');
|
||||
} else {
|
||||
$this->table([], [
|
||||
['Driver', $driver],
|
||||
['From Address', config('mail.from.address')],
|
||||
['From Name', config('mail.from.name')],
|
||||
], 'compact');
|
||||
}
|
||||
|
||||
$this->output->title('Backup Configuration');
|
||||
$driver = config('backups.default');
|
||||
if ($driver === 's3') {
|
||||
$this->table([], [
|
||||
['Driver', $driver],
|
||||
['Region', config("backups.disks.$driver.region")],
|
||||
['Bucket', config("backups.disks.$driver.bucket")],
|
||||
['Endpoint', config("backups.disks.$driver.endpoint")],
|
||||
['Use path style endpoint', config("backups.disks.$driver.use_path_style_endpoint") ? 'Yes' : 'No'],
|
||||
], 'compact');
|
||||
} else {
|
||||
$this->table([], [
|
||||
['Driver', $driver],
|
||||
], 'compact');
|
||||
}
|
||||
$this->table([], [
|
||||
['Driver', $this->config->get('mail.driver')],
|
||||
['Host', $this->config->get('mail.host')],
|
||||
['Port', $this->config->get('mail.port')],
|
||||
['Username', $this->config->get('mail.username')],
|
||||
['From Address', $this->config->get('mail.from.address')],
|
||||
['From Name', $this->config->get('mail.from.name')],
|
||||
['Encryption', $this->config->get('mail.encryption')],
|
||||
], 'compact');
|
||||
}
|
||||
|
||||
/**
|
||||
* Format output in a Name: Value manner.
|
||||
*
|
||||
* @param string $value
|
||||
* @param string $opts
|
||||
* @return string
|
||||
*/
|
||||
private function formatText(string $value, string $opts = ''): string
|
||||
private function formatText($value, $opts = '')
|
||||
{
|
||||
return sprintf('<%s>%s</>', $opts, $value);
|
||||
}
|
||||
|
||||
85
app/Console/Commands/Location/DeleteLocationCommand.php
Normal file
85
app/Console/Commands/Location/DeleteLocationCommand.php
Normal file
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
/**
|
||||
* Pterodactyl - Panel
|
||||
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
|
||||
*
|
||||
* This software is licensed under the terms of the MIT license.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
namespace Pterodactyl\Console\Commands\Location;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Pterodactyl\Services\Locations\LocationDeletionService;
|
||||
use Pterodactyl\Contracts\Repository\LocationRepositoryInterface;
|
||||
|
||||
class DeleteLocationCommand extends Command
|
||||
{
|
||||
/**
|
||||
* @var \Pterodactyl\Services\Locations\LocationDeletionService
|
||||
*/
|
||||
protected $deletionService;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Deletes a location from the Panel.';
|
||||
|
||||
/**
|
||||
* @var \Illuminate\Support\Collection
|
||||
*/
|
||||
protected $locations;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Contracts\Repository\LocationRepositoryInterface
|
||||
*/
|
||||
protected $repository;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'p:location:delete {--short= : The short code of the location to delete.}';
|
||||
|
||||
/**
|
||||
* DeleteLocationCommand constructor.
|
||||
*
|
||||
* @param \Pterodactyl\Contracts\Repository\LocationRepositoryInterface $repository
|
||||
* @param \Pterodactyl\Services\Locations\LocationDeletionService $deletionService
|
||||
*/
|
||||
public function __construct(
|
||||
LocationDeletionService $deletionService,
|
||||
LocationRepositoryInterface $repository
|
||||
) {
|
||||
parent::__construct();
|
||||
|
||||
$this->deletionService = $deletionService;
|
||||
$this->repository = $repository;
|
||||
}
|
||||
|
||||
/**
|
||||
* Respond to the command request.
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||
* @throws \Pterodactyl\Exceptions\Service\Location\HasActiveNodesException
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$this->locations = $this->locations ?? $this->repository->all();
|
||||
$short = $this->option('short') ?? $this->anticipate(
|
||||
trans('command/messages.location.ask_short'), $this->locations->pluck('short')->toArray()
|
||||
);
|
||||
|
||||
$location = $this->locations->where('short', $short)->first();
|
||||
if (is_null($location)) {
|
||||
$this->error(trans('command/messages.location.no_location_found'));
|
||||
if ($this->input->isInteractive()) {
|
||||
$this->handle();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->deletionService->handle($location->id);
|
||||
$this->line(trans('command/messages.location.deleted'));
|
||||
}
|
||||
}
|
||||
62
app/Console/Commands/Location/MakeLocationCommand.php
Normal file
62
app/Console/Commands/Location/MakeLocationCommand.php
Normal file
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
/**
|
||||
* Pterodactyl - Panel
|
||||
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
|
||||
*
|
||||
* This software is licensed under the terms of the MIT license.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
namespace Pterodactyl\Console\Commands\Location;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Pterodactyl\Services\Locations\LocationCreationService;
|
||||
|
||||
class MakeLocationCommand extends Command
|
||||
{
|
||||
/**
|
||||
* @var \Pterodactyl\Services\Locations\LocationCreationService
|
||||
*/
|
||||
protected $creationService;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'p:location:make
|
||||
{--short= : The shortcode name of this location (ex. us1).}
|
||||
{--long= : A longer description of this location.}';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Creates a new location on the system via the CLI.';
|
||||
|
||||
/**
|
||||
* Create a new command instance.
|
||||
*
|
||||
* @param \Pterodactyl\Services\Locations\LocationCreationService $creationService
|
||||
*/
|
||||
public function __construct(LocationCreationService $creationService)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->creationService = $creationService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the command execution process.
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$short = $this->option('short') ?? $this->ask(trans('command/messages.location.ask_short'));
|
||||
$long = $this->option('long') ?? $this->ask(trans('command/messages.location.ask_long'));
|
||||
|
||||
$location = $this->creationService->handle(compact('short', 'long'));
|
||||
$this->line(trans('command/messages.location.created', [
|
||||
'name' => $location->short,
|
||||
'id' => $location->id,
|
||||
]));
|
||||
}
|
||||
}
|
||||
@@ -1,24 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands\Maintenance;
|
||||
namespace Pterodactyl\Console\Commands\Maintenance;
|
||||
|
||||
use SplFileInfo;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Contracts\Filesystem\Filesystem;
|
||||
use Illuminate\Contracts\Filesystem\Factory as FilesystemFactory;
|
||||
|
||||
class CleanServiceBackupFilesCommand extends Command
|
||||
{
|
||||
public const BACKUP_THRESHOLD_MINUTES = 5;
|
||||
const BACKUP_THRESHOLD_MINUTES = 5;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Clean orphaned .bak files created when modifying services.';
|
||||
|
||||
protected $signature = 'p:maintenance:clean-service-backups';
|
||||
/**
|
||||
* @var \Illuminate\Contracts\Filesystem\Filesystem
|
||||
*/
|
||||
protected $disk;
|
||||
|
||||
protected Filesystem $disk;
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'p:maintenance:clean-service-backups';
|
||||
|
||||
/**
|
||||
* CleanServiceBackupFilesCommand constructor.
|
||||
*
|
||||
* @param \Illuminate\Contracts\Filesystem\Factory $filesystem
|
||||
*/
|
||||
public function __construct(FilesystemFactory $filesystem)
|
||||
{
|
||||
@@ -30,11 +41,11 @@ class CleanServiceBackupFilesCommand extends Command
|
||||
/**
|
||||
* Handle command execution.
|
||||
*/
|
||||
public function handle(): void
|
||||
public function handle()
|
||||
{
|
||||
$files = $this->disk->files('services/.bak');
|
||||
|
||||
collect($files)->each(function (\SplFileInfo $file) {
|
||||
collect($files)->each(function (SplFileInfo $file) {
|
||||
$lastModified = Carbon::createFromTimestamp($this->disk->lastModified($file->getPath()));
|
||||
if ($lastModified->diffInMinutes(Carbon::now()) > self::BACKUP_THRESHOLD_MINUTES) {
|
||||
$this->disk->delete($file->getPath());
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands\Maintenance;
|
||||
|
||||
use App\Models\Node;
|
||||
use Exception;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
|
||||
class PruneImagesCommand extends Command
|
||||
{
|
||||
protected $signature = 'p:maintenance:prune-images {node?}';
|
||||
|
||||
protected $description = 'Clean up all dangling docker images to clear up disk space.';
|
||||
|
||||
public function handle(): void
|
||||
{
|
||||
$node = $this->argument('node');
|
||||
|
||||
if (empty($node)) {
|
||||
$nodes = Node::all();
|
||||
/** @var Node $node */
|
||||
foreach ($nodes as $node) {
|
||||
$this->cleanupImages($node);
|
||||
}
|
||||
} else {
|
||||
$this->cleanupImages((int) $node);
|
||||
}
|
||||
}
|
||||
|
||||
private function cleanupImages(int|Node $node): void
|
||||
{
|
||||
if (!$node instanceof Node) {
|
||||
$node = Node::query()->findOrFail($node);
|
||||
}
|
||||
|
||||
try {
|
||||
$response = Http::daemon($node)
|
||||
->connectTimeout(5)
|
||||
->timeout(30)
|
||||
->delete('/api/system/docker/image/prune')
|
||||
->json() ?? [];
|
||||
|
||||
if (empty($response) || $response['ImagesDeleted'] === null) {
|
||||
$this->warn("Node {$node->id}: No images to clean up.");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$count = count($response['ImagesDeleted']);
|
||||
|
||||
$useBinaryPrefix = config('panel.use_binary_prefix');
|
||||
$space = round($useBinaryPrefix ? $response['SpaceReclaimed'] / 1024 / 1024 : $response['SpaceReclaimed'] / 1000 / 1000, 2) . ($useBinaryPrefix ? ' MiB' : ' MB');
|
||||
|
||||
$this->info("Node {$node->id}: Cleaned up {$count} dangling docker images. ({$space})");
|
||||
} catch (Exception $exception) {
|
||||
$this->error($exception->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands\Maintenance;
|
||||
|
||||
use App\Models\Backup;
|
||||
use Carbon\CarbonImmutable;
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
class PruneOrphanedBackupsCommand extends Command
|
||||
{
|
||||
protected $signature = 'p:maintenance:prune-backups {--prune-age=}';
|
||||
|
||||
protected $description = 'Marks all backups older than "n" minutes that have not yet completed as being failed.';
|
||||
|
||||
public function handle(): void
|
||||
{
|
||||
$since = $this->option('prune-age') ?? config('backups.prune_age', 360);
|
||||
if (!$since || !is_digit($since)) {
|
||||
throw new \InvalidArgumentException('The "--prune-age" argument must be a value greater than 0.');
|
||||
}
|
||||
|
||||
$query = Backup::query()
|
||||
->whereNull('completed_at')
|
||||
->where('created_at', '<=', CarbonImmutable::now()->subMinutes($since)->toDateTimeString());
|
||||
|
||||
$count = $query->count();
|
||||
if (!$count) {
|
||||
$this->info('There are no orphaned backups to be marked as failed.');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->warn("Marking $count uncompleted backups that are older than $since minutes as failed.");
|
||||
|
||||
$query->update([
|
||||
'is_successful' => false,
|
||||
'completed_at' => CarbonImmutable::now(),
|
||||
'updated_at' => CarbonImmutable::now(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
namespace Pterodactyl\Console\Commands\Migration;
|
||||
|
||||
use Pterodactyl\Models\ApiKey;
|
||||
use Illuminate\Console\Command;
|
||||
use Pterodactyl\Contracts\Repository\ApiKeyRepositoryInterface;
|
||||
|
||||
class CleanOrphanedApiKeysCommand extends Command
|
||||
{
|
||||
/**
|
||||
* @var \Pterodactyl\Contracts\Repository\ApiKeyRepositoryInterface
|
||||
*/
|
||||
private $repository;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'p:migration:clean-orphaned-keys';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Cleans API keys from the database that are not assigned a specific role.';
|
||||
|
||||
/**
|
||||
* CleanOrphanedApiKeysCommand constructor.
|
||||
*
|
||||
* @param \Pterodactyl\Contracts\Repository\ApiKeyRepositoryInterface $repository
|
||||
*/
|
||||
public function __construct(ApiKeyRepositoryInterface $repository)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->repository = $repository;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all orphaned API keys from the database when upgrading from 0.6 to 0.7.
|
||||
*
|
||||
* @return null|void
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$count = $this->repository->findCountWhere([['key_type', '=', ApiKey::TYPE_NONE]]);
|
||||
$continue = $this->confirm(
|
||||
'This action will remove ' . $count . ' keys from the database. Are you sure you wish to continue?', false
|
||||
);
|
||||
|
||||
if (! $continue) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$this->info('Deleting keys...');
|
||||
$this->repository->deleteWhere([['key_type', '=', ApiKey::TYPE_NONE]]);
|
||||
$this->info('Keys were successfully deleted.');
|
||||
}
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands\Node;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use App\Services\Nodes\NodeCreationService;
|
||||
|
||||
class MakeNodeCommand extends Command
|
||||
{
|
||||
protected $signature = 'p:node:make
|
||||
{--name= : A name to identify the node.}
|
||||
{--description= : A description to identify the node.}
|
||||
{--locationId= : A valid locationId.}
|
||||
{--fqdn= : The domain name (e.g node.example.com) to be used for connecting to the daemon. An IP address may only be used if you are not using SSL for this node.}
|
||||
{--public= : Should the node be public or private? (public=1 / private=0).}
|
||||
{--scheme= : Which scheme should be used? (Enable SSL=https / Disable SSL=http).}
|
||||
{--proxy= : Is the daemon behind a proxy? (Yes=1 / No=0).}
|
||||
{--maintenance= : Should maintenance mode be enabled? (Enable Maintenance mode=1 / Disable Maintenance mode=0).}
|
||||
{--maxMemory= : Set the max memory amount.}
|
||||
{--overallocateMemory= : Enter the amount of ram to overallocate (% or -1 to overallocate the maximum).}
|
||||
{--maxDisk= : Set the max disk amount.}
|
||||
{--overallocateDisk= : Enter the amount of disk to overallocate (% or -1 to overallocate the maximum).}
|
||||
{--maxCpu= : Set the max cpu amount.}
|
||||
{--overallocateCpu= : Enter the amount of cpu to overallocate (% or -1 to overallocate the maximum).}
|
||||
{--uploadSize= : Enter the maximum upload filesize.}
|
||||
{--daemonListeningPort= : Enter the daemon listening port.}
|
||||
{--daemonSFTPPort= : Enter the daemon SFTP listening port.}
|
||||
{--daemonSFTPAlias= : Enter the daemon SFTP alias.}
|
||||
{--daemonBase= : Enter the base folder.}';
|
||||
|
||||
protected $description = 'Creates a new node on the system via the CLI.';
|
||||
|
||||
/**
|
||||
* MakeNodeCommand constructor.
|
||||
*/
|
||||
public function __construct(private NodeCreationService $creationService)
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the command execution process.
|
||||
*
|
||||
* @throws \App\Exceptions\Model\DataValidationException
|
||||
*/
|
||||
public function handle(): void
|
||||
{
|
||||
$data['name'] = $this->option('name') ?? $this->ask(__('commands.make_node.name'));
|
||||
$data['description'] = $this->option('description') ?? $this->ask(__('commands.make_node.description'));
|
||||
$data['scheme'] = $this->option('scheme') ?? $this->anticipate(
|
||||
__('commands.make_node.scheme'),
|
||||
['https', 'http'],
|
||||
'https'
|
||||
);
|
||||
|
||||
$data['fqdn'] = $this->option('fqdn') ?? $this->ask(__('commands.make_node.fqdn'));
|
||||
$data['public'] = $this->option('public') ?? $this->confirm(__('commands.make_node.public'), true);
|
||||
$data['behind_proxy'] = $this->option('proxy') ?? $this->confirm(__('commands.make_node.behind_proxy'));
|
||||
$data['maintenance_mode'] = $this->option('maintenance') ?? $this->confirm(__('commands.make_node.maintenance_mode'));
|
||||
$data['memory'] = $this->option('maxMemory') ?? $this->ask(__('commands.make_node.memory'), '0');
|
||||
$data['memory_overallocate'] = $this->option('overallocateMemory') ?? $this->ask(__('commands.make_node.memory_overallocate'), '-1');
|
||||
$data['disk'] = $this->option('maxDisk') ?? $this->ask(__('commands.make_node.disk'), '0');
|
||||
$data['disk_overallocate'] = $this->option('overallocateDisk') ?? $this->ask(__('commands.make_node.disk_overallocate'), '-1');
|
||||
$data['cpu'] = $this->option('maxCpu') ?? $this->ask(__('commands.make_node.cpu'), '0');
|
||||
$data['cpu_overallocate'] = $this->option('overallocateCpu') ?? $this->ask(__('commands.make_node.cpu_overallocate'), '-1');
|
||||
$data['upload_size'] = $this->option('uploadSize') ?? $this->ask(__('commands.make_node.upload_size'), '256');
|
||||
$data['daemon_listen'] = $this->option('daemonListeningPort') ?? $this->ask(__('commands.make_node.daemonListen'), '8080');
|
||||
$data['daemon_sftp'] = $this->option('daemonSFTPPort') ?? $this->ask(__('commands.make_node.daemonSFTP'), '2022');
|
||||
$data['daemon_sftp_alias'] = $this->option('daemonSFTPAlias') ?? $this->ask(__('commands.make_node.daemonSFTPAlias'), '');
|
||||
$data['daemon_base'] = $this->option('daemonBase') ?? $this->ask(__('commands.make_node.daemonBase'), '/var/lib/pelican/volumes');
|
||||
|
||||
$node = $this->creationService->handle($data);
|
||||
$this->line(__('commands.make_node.success', ['name' => $data['name'], 'id' => $node->id]));
|
||||
}
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands\Node;
|
||||
|
||||
use App\Models\Node;
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
class NodeConfigurationCommand extends Command
|
||||
{
|
||||
protected $signature = 'p:node:configuration
|
||||
{node : The ID or UUID of the node to return the configuration for.}
|
||||
{--format=yaml : The output format. Options are "yaml" and "json".}';
|
||||
|
||||
protected $description = 'Displays the configuration for the specified node.';
|
||||
|
||||
public function handle(): int
|
||||
{
|
||||
$column = ctype_digit((string) $this->argument('node')) ? 'id' : 'uuid';
|
||||
|
||||
/** @var \App\Models\Node $node */
|
||||
$node = Node::query()->where($column, $this->argument('node'))->firstOr(function () {
|
||||
$this->error(__('commands.node_config.error_not_exist'));
|
||||
|
||||
exit(1);
|
||||
});
|
||||
|
||||
$format = $this->option('format');
|
||||
if (!in_array($format, ['yaml', 'yml', 'json'])) {
|
||||
$this->error(__('commands.node_config.error_invalid_format'));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ($format === 'json') {
|
||||
$this->output->write($node->getJsonConfiguration(true));
|
||||
} else {
|
||||
$this->output->write($node->getYamlConfiguration());
|
||||
}
|
||||
|
||||
$this->output->newLine();
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands\Node;
|
||||
|
||||
use App\Models\Node;
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
class NodeListCommand extends Command
|
||||
{
|
||||
protected $signature = 'p:node:list {--format=text : The output format: "text" or "json". }';
|
||||
|
||||
public function handle(): int
|
||||
{
|
||||
$nodes = Node::query()->get()->map(function (Node $node) {
|
||||
return [
|
||||
'id' => $node->id,
|
||||
'uuid' => $node->uuid,
|
||||
'name' => $node->name,
|
||||
'host' => $node->getConnectionAddress(),
|
||||
];
|
||||
});
|
||||
|
||||
if ($this->option('format') === 'json') {
|
||||
$this->output->write($nodes->toJson(JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
|
||||
} else {
|
||||
$this->table(['ID', 'UUID', 'Name', 'Host'], $nodes->toArray());
|
||||
}
|
||||
|
||||
$this->output->newLine();
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands\Overrides;
|
||||
namespace Pterodactyl\Console\Commands\Overrides;
|
||||
|
||||
use Illuminate\Foundation\Console\KeyGenerateCommand as BaseKeyGenerateCommand;
|
||||
|
||||
@@ -10,15 +10,15 @@ class KeyGenerateCommand extends BaseKeyGenerateCommand
|
||||
* Override the default Laravel key generation command to throw a warning to the user
|
||||
* if it appears that they have already generated an application encryption key.
|
||||
*/
|
||||
public function handle(): void
|
||||
public function handle()
|
||||
{
|
||||
if (!empty(config('app.key')) && $this->input->isInteractive()) {
|
||||
$this->output->warning(__('commands.key_generate.error_already_exist'));
|
||||
if (!$this->confirm(__('commands.key_generate.understand'))) {
|
||||
if (! empty(config('app.key')) && $this->input->isInteractive()) {
|
||||
$this->output->warning(trans('command/messages.key.warning'));
|
||||
if (! $this->confirm(trans('command/messages.key.confirm'))) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$this->confirm(__('commands.key_generate.continue'))) {
|
||||
if (! $this->confirm(trans('command/messages.key.final_confirm'))) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands\Overrides;
|
||||
|
||||
use App\Traits\Commands\RequiresDatabaseMigrations;
|
||||
use Illuminate\Database\Console\Seeds\SeedCommand as BaseSeedCommand;
|
||||
|
||||
class SeedCommand extends BaseSeedCommand
|
||||
{
|
||||
use RequiresDatabaseMigrations;
|
||||
|
||||
/**
|
||||
* Block someone from running this seed command if they have not completed
|
||||
* the migration process.
|
||||
*/
|
||||
public function handle(): int
|
||||
{
|
||||
if (!$this->hasCompletedMigrations()) {
|
||||
$this->showMigrationWarning();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return parent::handle();
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands\Overrides;
|
||||
|
||||
use App\Traits\Commands\RequiresDatabaseMigrations;
|
||||
use Illuminate\Foundation\Console\UpCommand as BaseUpCommand;
|
||||
|
||||
class UpCommand extends BaseUpCommand
|
||||
{
|
||||
use RequiresDatabaseMigrations;
|
||||
|
||||
/**
|
||||
* Block someone from running this up command if they have not completed
|
||||
* the migration process.
|
||||
*/
|
||||
public function handle(): int
|
||||
{
|
||||
if (!$this->hasCompletedMigrations()) {
|
||||
$this->showMigrationWarning();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return parent::handle();
|
||||
}
|
||||
}
|
||||
@@ -1,73 +1,86 @@
|
||||
<?php
|
||||
/**
|
||||
* Pterodactyl - Panel
|
||||
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
|
||||
*
|
||||
* This software is licensed under the terms of the MIT license.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
namespace App\Console\Commands\Schedule;
|
||||
namespace Pterodactyl\Console\Commands\Schedule;
|
||||
|
||||
use Cake\Chronos\Chronos;
|
||||
use Illuminate\Console\Command;
|
||||
use App\Models\Schedule;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use App\Services\Schedules\ProcessScheduleService;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\Collection;
|
||||
use Pterodactyl\Services\Schedules\ProcessScheduleService;
|
||||
use Pterodactyl\Contracts\Repository\ScheduleRepositoryInterface;
|
||||
|
||||
class ProcessRunnableCommand extends Command
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Process schedules in the database and determine which are ready to run.';
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Services\Schedules\ProcessScheduleService
|
||||
*/
|
||||
protected $processScheduleService;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Contracts\Repository\ScheduleRepositoryInterface
|
||||
*/
|
||||
protected $repository;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'p:schedule:process';
|
||||
|
||||
protected $description = 'Process schedules in the database and determine which are ready to run.';
|
||||
/**
|
||||
* ProcessRunnableCommand constructor.
|
||||
*
|
||||
* @param \Pterodactyl\Services\Schedules\ProcessScheduleService $processScheduleService
|
||||
* @param \Pterodactyl\Contracts\Repository\ScheduleRepositoryInterface $repository
|
||||
*/
|
||||
public function __construct(ProcessScheduleService $processScheduleService, ScheduleRepositoryInterface $repository)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->processScheduleService = $processScheduleService;
|
||||
$this->repository = $repository;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle command execution.
|
||||
*/
|
||||
public function handle(): int
|
||||
public function handle()
|
||||
{
|
||||
$schedules = Schedule::query()
|
||||
->with('tasks')
|
||||
->whereRelation('server', fn (Builder $builder) => $builder->whereNull('status'))
|
||||
->where('is_active', true)
|
||||
->where('is_processing', false)
|
||||
->where('next_run_at', '<=', Carbon::now()->toDateTimeString())
|
||||
->get();
|
||||
|
||||
$schedules = $this->repository->getSchedulesToProcess(Chronos::now()->toAtomString());
|
||||
if ($schedules->count() < 1) {
|
||||
$this->line(__('commands.schedule.process.no_tasks'));
|
||||
$this->line('There are no scheduled tasks for servers that need to be run.');
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
$bar = $this->output->createProgressBar(count($schedules));
|
||||
foreach ($schedules as $schedule) {
|
||||
$bar->clear();
|
||||
$this->processSchedule($schedule);
|
||||
$bar->advance();
|
||||
$bar->display();
|
||||
}
|
||||
|
||||
$this->line('');
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a given schedule and logs and errors encountered the console output. This should
|
||||
* never throw an exception out, otherwise you'll end up killing the entire run group causing
|
||||
* any other schedules to not process correctly.
|
||||
*/
|
||||
protected function processSchedule(Schedule $schedule): void
|
||||
{
|
||||
if ($schedule->tasks->isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
$this->getLaravel()->make(ProcessScheduleService::class)->handle($schedule);
|
||||
$bar = $this->output->createProgressBar(count($schedules));
|
||||
$schedules->each(function ($schedule) use ($bar) {
|
||||
if ($schedule->tasks instanceof Collection && count($schedule->tasks) > 0) {
|
||||
$this->processScheduleService->handle($schedule);
|
||||
|
||||
$this->line(trans('command/messages.schedule.output_line', [
|
||||
'schedule' => $schedule->name,
|
||||
'id' => $schedule->id,
|
||||
]));
|
||||
} catch (\Throwable|\Exception $exception) {
|
||||
logger()->error($exception, ['schedule_id' => $schedule->id]);
|
||||
if ($this->input->isInteractive()) {
|
||||
$bar->clear();
|
||||
$this->line(trans('command/messages.schedule.output_line', [
|
||||
'schedule' => $schedule->name,
|
||||
'hash' => $schedule->hashid,
|
||||
]));
|
||||
}
|
||||
}
|
||||
|
||||
$this->error(__('commands.schedule.process.no_tasks') . " #$schedule->id: " . $exception->getMessage());
|
||||
}
|
||||
$bar->advance();
|
||||
$bar->display();
|
||||
});
|
||||
|
||||
$this->line('');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,38 +1,70 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands\Server;
|
||||
namespace Pterodactyl\Console\Commands\Server;
|
||||
|
||||
use App\Models\Server;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use GuzzleHttp\Exception\RequestException;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use Illuminate\Validation\Factory as ValidatorFactory;
|
||||
use App\Repositories\Daemon\DaemonPowerRepository;
|
||||
use App\Exceptions\Http\Connection\DaemonConnectionException;
|
||||
use Pterodactyl\Contracts\Repository\ServerRepositoryInterface;
|
||||
use Pterodactyl\Contracts\Repository\Daemon\PowerRepositoryInterface;
|
||||
|
||||
class BulkPowerActionCommand extends Command
|
||||
{
|
||||
/**
|
||||
* @var \Pterodactyl\Contracts\Repository\Daemon\PowerRepositoryInterface
|
||||
*/
|
||||
private $powerRepository;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Contracts\Repository\ServerRepositoryInterface
|
||||
*/
|
||||
private $repository;
|
||||
|
||||
/**
|
||||
* @var \Illuminate\Validation\Factory
|
||||
*/
|
||||
private $validator;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'p:server:bulk-power
|
||||
{action : The action to perform (start, stop, restart, kill)}
|
||||
{--servers= : A comma separated list of servers.}
|
||||
{--nodes= : A comma separated list of nodes.}';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Perform bulk power management on large groupings of servers or nodes at once.';
|
||||
|
||||
/**
|
||||
* BulkPowerActionCommand constructor.
|
||||
*
|
||||
* @param \Pterodactyl\Contracts\Repository\Daemon\PowerRepositoryInterface $powerRepository
|
||||
* @param \Pterodactyl\Contracts\Repository\ServerRepositoryInterface $repository
|
||||
* @param \Illuminate\Validation\Factory $validator
|
||||
*/
|
||||
public function __construct(private DaemonPowerRepository $powerRepository, private ValidatorFactory $validator)
|
||||
{
|
||||
public function __construct(
|
||||
PowerRepositoryInterface $powerRepository,
|
||||
ServerRepositoryInterface $repository,
|
||||
ValidatorFactory $validator
|
||||
) {
|
||||
parent::__construct();
|
||||
|
||||
$this->powerRepository = $powerRepository;
|
||||
$this->repository = $repository;
|
||||
$this->validator = $validator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the bulk power request.
|
||||
*
|
||||
* @throws \Illuminate\Validation\ValidationException
|
||||
* @throws \Pterodactyl\Exceptions\Repository\Daemon\InvalidPowerSignalException
|
||||
*/
|
||||
public function handle(): void
|
||||
public function handle()
|
||||
{
|
||||
$action = $this->argument('action');
|
||||
$nodes = empty($this->option('nodes')) ? [] : explode(',', $this->option('nodes'));
|
||||
@@ -58,19 +90,23 @@ class BulkPowerActionCommand extends Command
|
||||
throw new ValidationException($validator);
|
||||
}
|
||||
|
||||
$count = $this->getQueryBuilder($servers, $nodes)->count();
|
||||
if (!$this->confirm(trans('command/messages.server.power.confirm', ['action' => $action, 'count' => $count])) && $this->input->isInteractive()) {
|
||||
$count = $this->repository->getServersForPowerActionCount($servers, $nodes);
|
||||
if (! $this->confirm(trans('command/messages.server.power.confirm', ['action' => $action, 'count' => $count]))) {
|
||||
return;
|
||||
}
|
||||
|
||||
$bar = $this->output->createProgressBar($count);
|
||||
$powerRepository = $this->powerRepository;
|
||||
$this->getQueryBuilder($servers, $nodes)->each(function (Server $server) use ($action, $powerRepository, &$bar) {
|
||||
$servers = $this->repository->getServersForPowerAction($servers, $nodes);
|
||||
|
||||
foreach ($servers as $server) {
|
||||
$bar->clear();
|
||||
|
||||
try {
|
||||
$powerRepository->setServer($server)->send($action);
|
||||
} catch (DaemonConnectionException $exception) {
|
||||
$this->powerRepository
|
||||
->setNode($server->node)
|
||||
->setServer($server)
|
||||
->sendSignal($action);
|
||||
} catch (RequestException $exception) {
|
||||
$this->output->error(trans('command/messages.server.power.action_failed', [
|
||||
'name' => $server->name,
|
||||
'id' => $server->id,
|
||||
@@ -81,26 +117,8 @@ class BulkPowerActionCommand extends Command
|
||||
|
||||
$bar->advance();
|
||||
$bar->display();
|
||||
});
|
||||
}
|
||||
|
||||
$this->line('');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the query builder instance that will return the servers that should be affected.
|
||||
*/
|
||||
protected function getQueryBuilder(array $servers, array $nodes): Builder
|
||||
{
|
||||
$instance = Server::query()->whereNull('status');
|
||||
|
||||
if (!empty($nodes) && !empty($servers)) {
|
||||
$instance->whereIn('id', $servers)->orWhereIn('node_id', $nodes);
|
||||
} elseif (empty($nodes) && !empty($servers)) {
|
||||
$instance->whereIn('id', $servers);
|
||||
} elseif (!empty($nodes)) {
|
||||
$instance->whereIn('node_id', $nodes);
|
||||
}
|
||||
|
||||
return $instance->with('node');
|
||||
}
|
||||
}
|
||||
|
||||
109
app/Console/Commands/Server/RebuildServerCommand.php
Normal file
109
app/Console/Commands/Server/RebuildServerCommand.php
Normal file
@@ -0,0 +1,109 @@
|
||||
<?php
|
||||
/**
|
||||
* Pterodactyl - Panel
|
||||
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
|
||||
*
|
||||
* This software is licensed under the terms of the MIT license.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
namespace Pterodactyl\Console\Commands\Server;
|
||||
|
||||
use Webmozart\Assert\Assert;
|
||||
use Illuminate\Console\Command;
|
||||
use GuzzleHttp\Exception\RequestException;
|
||||
use Pterodactyl\Contracts\Repository\ServerRepositoryInterface;
|
||||
use Pterodactyl\Services\Servers\ServerConfigurationStructureService;
|
||||
use Pterodactyl\Contracts\Repository\Daemon\ServerRepositoryInterface as DaemonServerRepositoryInterface;
|
||||
|
||||
class RebuildServerCommand extends Command
|
||||
{
|
||||
/**
|
||||
* @var \Pterodactyl\Services\Servers\ServerConfigurationStructureService
|
||||
*/
|
||||
protected $configurationStructureService;
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Contracts\Repository\Daemon\ServerRepositoryInterface
|
||||
*/
|
||||
protected $daemonRepository;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Rebuild a single server, all servers on a node, or all servers on the panel.';
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Contracts\Repository\ServerRepositoryInterface
|
||||
*/
|
||||
protected $repository;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'p:server:rebuild
|
||||
{server? : The ID of the server to rebuild.}
|
||||
{--node= : ID of the node to rebuild all servers on. Ignored if server is passed.}';
|
||||
|
||||
/**
|
||||
* RebuildServerCommand constructor.
|
||||
*
|
||||
* @param \Pterodactyl\Contracts\Repository\Daemon\ServerRepositoryInterface $daemonRepository
|
||||
* @param \Pterodactyl\Services\Servers\ServerConfigurationStructureService $configurationStructureService
|
||||
* @param \Pterodactyl\Contracts\Repository\ServerRepositoryInterface $repository
|
||||
*/
|
||||
public function __construct(
|
||||
DaemonServerRepositoryInterface $daemonRepository,
|
||||
ServerConfigurationStructureService $configurationStructureService,
|
||||
ServerRepositoryInterface $repository
|
||||
) {
|
||||
parent::__construct();
|
||||
|
||||
$this->configurationStructureService = $configurationStructureService;
|
||||
$this->daemonRepository = $daemonRepository;
|
||||
$this->repository = $repository;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle command execution.
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$servers = $this->getServersToProcess();
|
||||
$bar = $this->output->createProgressBar(count($servers));
|
||||
|
||||
$servers->each(function ($server) use ($bar) {
|
||||
$bar->clear();
|
||||
$json = array_merge($this->configurationStructureService->handle($server), ['rebuild' => true]);
|
||||
|
||||
try {
|
||||
$this->daemonRepository->setServer($server)->update($json);
|
||||
} catch (RequestException $exception) {
|
||||
$this->output->error(trans('command/messages.server.rebuild_failed', [
|
||||
'name' => $server->name,
|
||||
'id' => $server->id,
|
||||
'node' => $server->node->name,
|
||||
'message' => $exception->getMessage(),
|
||||
]));
|
||||
}
|
||||
|
||||
$bar->advance();
|
||||
$bar->display();
|
||||
});
|
||||
|
||||
$this->line('');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the servers to be rebuilt.
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Collection
|
||||
*/
|
||||
private function getServersToProcess()
|
||||
{
|
||||
Assert::nullOrIntegerish($this->argument('server'), 'Value passed in server argument must be null or an integer, received %s.');
|
||||
Assert::nullOrIntegerish($this->option('node'), 'Value passed in node option must be null or integer, received %s.');
|
||||
|
||||
return $this->repository->getDataForRebuild($this->argument('server'), $this->option('node'));
|
||||
}
|
||||
}
|
||||
@@ -1,197 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use App\Console\Kernel;
|
||||
use Symfony\Component\Process\Process;
|
||||
use Symfony\Component\Console\Helper\ProgressBar;
|
||||
|
||||
class UpgradeCommand extends Command
|
||||
{
|
||||
protected const DEFAULT_URL = 'https://github.com/pelican-dev/panel/releases/%s/panel.tar.gz';
|
||||
|
||||
protected $signature = 'p:upgrade
|
||||
{--user= : The user that PHP runs under. All files will be owned by this user.}
|
||||
{--group= : The group that PHP runs under. All files will be owned by this group.}
|
||||
{--url= : The specific archive to download.}
|
||||
{--release= : A specific version to download from GitHub. Leave blank to use latest.}
|
||||
{--skip-download : If set no archive will be downloaded.}';
|
||||
|
||||
protected $description = 'Downloads a new archive from GitHub and then executes the normal upgrade commands.';
|
||||
|
||||
/**
|
||||
* Executes an upgrade command which will run through all of our standard
|
||||
* Panel commands and enable users to basically just download
|
||||
* the archive and execute this and be done.
|
||||
*
|
||||
* This places the application in maintenance mode as well while the commands
|
||||
* are being executed.
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function handle(): void
|
||||
{
|
||||
$skipDownload = $this->option('skip-download');
|
||||
if (!$skipDownload) {
|
||||
$this->output->warning(__('commands.upgrade.integrity'));
|
||||
$this->output->comment(__('commands.upgrade.source_url'));
|
||||
$this->line($this->getUrl());
|
||||
}
|
||||
|
||||
if (version_compare(PHP_VERSION, '7.4.0') < 0) {
|
||||
$this->error(__('commands.upgrade.php_version') . ' [' . PHP_VERSION . '].');
|
||||
}
|
||||
|
||||
$user = 'www-data';
|
||||
$group = 'www-data';
|
||||
if ($this->input->isInteractive()) {
|
||||
if (!$skipDownload) {
|
||||
$skipDownload = !$this->confirm(__('commands.upgrade.skipDownload'), true);
|
||||
}
|
||||
|
||||
if (is_null($this->option('user'))) {
|
||||
$userDetails = function_exists('posix_getpwuid') ? posix_getpwuid(fileowner('public')) : [];
|
||||
$user = $userDetails['name'] ?? 'www-data';
|
||||
|
||||
$message = __('commands.upgrade.webserver_user', ['user' => $user]);
|
||||
if (!$this->confirm($message, true)) {
|
||||
$user = $this->anticipate(
|
||||
__('commands.upgrade.name_webserver'),
|
||||
[
|
||||
'www-data',
|
||||
'nginx',
|
||||
'apache',
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (is_null($this->option('group'))) {
|
||||
$groupDetails = function_exists('posix_getgrgid') ? posix_getgrgid(filegroup('public')) : [];
|
||||
$group = $groupDetails['name'] ?? 'www-data';
|
||||
|
||||
$message = __('commands.upgrade.group_webserver', ['group' => $user]);
|
||||
if (!$this->confirm($message, true)) {
|
||||
$group = $this->anticipate(
|
||||
__('commands.upgrade.group_webserver_question'),
|
||||
[
|
||||
'www-data',
|
||||
'nginx',
|
||||
'apache',
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (!$this->confirm(__('commands.upgrade.are_your_sure'))) {
|
||||
$this->warn(__('commands.upgrade.terminated'));
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ini_set('output_buffering', '0');
|
||||
$bar = $this->output->createProgressBar($skipDownload ? 9 : 10);
|
||||
$bar->start();
|
||||
|
||||
if (!$skipDownload) {
|
||||
$this->withProgress($bar, function () {
|
||||
$this->line("\$upgrader> curl -L \"{$this->getUrl()}\" | tar -xzv");
|
||||
$process = Process::fromShellCommandline("curl -L \"{$this->getUrl()}\" | tar -xzv");
|
||||
$process->run(function ($type, $buffer) {
|
||||
$this->{$type === Process::ERR ? 'error' : 'line'}($buffer);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
$this->withProgress($bar, function () {
|
||||
$this->line('$upgrader> php artisan down');
|
||||
$this->call('down');
|
||||
});
|
||||
|
||||
$this->withProgress($bar, function () {
|
||||
$this->line('$upgrader> chmod -R 755 storage bootstrap/cache');
|
||||
$process = new Process(['chmod', '-R', '755', 'storage', 'bootstrap/cache']);
|
||||
$process->run(function ($type, $buffer) {
|
||||
$this->{$type === Process::ERR ? 'error' : 'line'}($buffer);
|
||||
});
|
||||
});
|
||||
|
||||
$this->withProgress($bar, function () {
|
||||
$command = ['composer', 'install', '--no-ansi'];
|
||||
if (config('app.env') === 'production' && !config('app.debug')) {
|
||||
$command[] = '--optimize-autoloader';
|
||||
$command[] = '--no-dev';
|
||||
}
|
||||
|
||||
$this->line('$upgrader> ' . implode(' ', $command));
|
||||
$process = new Process($command);
|
||||
$process->setTimeout(10 * 60);
|
||||
$process->run(function ($type, $buffer) {
|
||||
$this->line($buffer);
|
||||
});
|
||||
});
|
||||
|
||||
/** @var \Illuminate\Foundation\Application $app */
|
||||
$app = require __DIR__ . '/../../../bootstrap/app.php';
|
||||
/** @var \App\Console\Kernel $kernel */
|
||||
$kernel = $app->make(Kernel::class);
|
||||
$kernel->bootstrap();
|
||||
$this->setLaravel($app);
|
||||
|
||||
$this->withProgress($bar, function () {
|
||||
$this->line('$upgrader> php artisan view:clear');
|
||||
$this->call('view:clear');
|
||||
});
|
||||
|
||||
$this->withProgress($bar, function () {
|
||||
$this->line('$upgrader> php artisan config:clear');
|
||||
$this->call('config:clear');
|
||||
});
|
||||
|
||||
$this->withProgress($bar, function () {
|
||||
$this->line('$upgrader> php artisan migrate --force --seed');
|
||||
$this->call('migrate', ['--force' => true, '--seed' => true]);
|
||||
});
|
||||
|
||||
$this->withProgress($bar, function () use ($user, $group) {
|
||||
$this->line("\$upgrader> chown -R {$user}:{$group} *");
|
||||
$process = Process::fromShellCommandline("chown -R {$user}:{$group} *", $this->getLaravel()->basePath());
|
||||
$process->setTimeout(10 * 60);
|
||||
$process->run(function ($type, $buffer) {
|
||||
$this->{$type === Process::ERR ? 'error' : 'line'}($buffer);
|
||||
});
|
||||
});
|
||||
|
||||
$this->withProgress($bar, function () {
|
||||
$this->line('$upgrader> php artisan queue:restart');
|
||||
$this->call('queue:restart');
|
||||
});
|
||||
|
||||
$this->withProgress($bar, function () {
|
||||
$this->line('$upgrader> php artisan up');
|
||||
$this->call('up');
|
||||
});
|
||||
|
||||
$this->newLine(2);
|
||||
$this->info(__('commands.upgrade.success'));
|
||||
}
|
||||
|
||||
protected function withProgress(ProgressBar $bar, \Closure $callback): void
|
||||
{
|
||||
$bar->clear();
|
||||
$callback();
|
||||
$bar->advance();
|
||||
$bar->display();
|
||||
}
|
||||
|
||||
protected function getUrl(): string
|
||||
{
|
||||
if ($this->option('url')) {
|
||||
return $this->option('url');
|
||||
}
|
||||
|
||||
return sprintf(self::DEFAULT_URL, $this->option('release') ? 'download/v' . $this->option('release') : 'latest/download');
|
||||
}
|
||||
}
|
||||
@@ -1,35 +1,74 @@
|
||||
<?php
|
||||
/**
|
||||
* Pterodactyl - Panel
|
||||
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
|
||||
*
|
||||
* This software is licensed under the terms of the MIT license.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
namespace App\Console\Commands\User;
|
||||
namespace Pterodactyl\Console\Commands\User;
|
||||
|
||||
use App\Models\User;
|
||||
use Webmozart\Assert\Assert;
|
||||
use Illuminate\Console\Command;
|
||||
use Pterodactyl\Services\Users\UserDeletionService;
|
||||
use Pterodactyl\Contracts\Repository\UserRepositoryInterface;
|
||||
|
||||
class DeleteUserCommand extends Command
|
||||
{
|
||||
/**
|
||||
* @var \Pterodactyl\Services\Users\UserDeletionService
|
||||
*/
|
||||
protected $deletionService;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Deletes a user from the Panel if no servers are attached to their account.';
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Contracts\Repository\UserRepositoryInterface
|
||||
*/
|
||||
protected $repository;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'p:user:delete {--user=}';
|
||||
|
||||
public function handle(): int
|
||||
/**
|
||||
* DeleteUserCommand constructor.
|
||||
*
|
||||
* @param \Pterodactyl\Services\Users\UserDeletionService $deletionService
|
||||
* @param \Pterodactyl\Contracts\Repository\UserRepositoryInterface $repository
|
||||
*/
|
||||
public function __construct(
|
||||
UserDeletionService $deletionService,
|
||||
UserRepositoryInterface $repository
|
||||
) {
|
||||
parent::__construct();
|
||||
|
||||
$this->deletionService = $deletionService;
|
||||
$this->repository = $repository;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
* @throws \Pterodactyl\Exceptions\DisplayException
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$search = $this->option('user') ?? $this->ask(trans('command/messages.user.search_users'));
|
||||
Assert::notEmpty($search, 'Search term should not be empty.');
|
||||
|
||||
$results = User::query()
|
||||
->where('id', 'LIKE', "$search%")
|
||||
->orWhere('username', 'LIKE', "$search%")
|
||||
->orWhere('email', 'LIKE', "$search%")
|
||||
->get();
|
||||
Assert::notEmpty($search, 'Search term must be a non-null value, received %s.');
|
||||
|
||||
$results = $this->repository->setSearchTerm($search)->all();
|
||||
if (count($results) < 1) {
|
||||
$this->error(trans('command/messages.user.no_users_found'));
|
||||
if ($this->input->isInteractive()) {
|
||||
return $this->handle();
|
||||
}
|
||||
|
||||
return 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->input->isInteractive()) {
|
||||
@@ -39,27 +78,22 @@ class DeleteUserCommand extends Command
|
||||
}
|
||||
|
||||
$this->table(['User ID', 'Email', 'Name'], $tableValues);
|
||||
if (!$deleteUser = $this->ask(trans('command/messages.user.select_search_user'))) {
|
||||
if (! $deleteUser = $this->ask(trans('command/messages.user.select_search_user'))) {
|
||||
return $this->handle();
|
||||
}
|
||||
|
||||
$deleteUser = User::query()->findOrFail($deleteUser);
|
||||
} else {
|
||||
if (count($results) > 1) {
|
||||
$this->error(trans('command/messages.user.multiple_found'));
|
||||
|
||||
return 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
$deleteUser = $results->first();
|
||||
}
|
||||
|
||||
if ($this->confirm(trans('command/messages.user.confirm_delete')) || !$this->input->isInteractive()) {
|
||||
$deleteUser->delete();
|
||||
|
||||
if ($this->confirm(trans('command/messages.user.confirm_delete')) || ! $this->input->isInteractive()) {
|
||||
$this->deletionService->handle($deleteUser);
|
||||
$this->info(trans('command/messages.user.deleted'));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,34 +1,65 @@
|
||||
<?php
|
||||
/**
|
||||
* Pterodactyl - Panel
|
||||
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
|
||||
*
|
||||
* This software is licensed under the terms of the MIT license.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
namespace App\Console\Commands\User;
|
||||
namespace Pterodactyl\Console\Commands\User;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Console\Command;
|
||||
use Pterodactyl\Contracts\Repository\UserRepositoryInterface;
|
||||
|
||||
class DisableTwoFactorCommand extends Command
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Disable two-factor authentication for a specific user in the Panel.';
|
||||
|
||||
/**
|
||||
* @var \Pterodactyl\Contracts\Repository\UserRepositoryInterface
|
||||
*/
|
||||
protected $repository;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'p:user:disable2fa {--email= : The email of the user to disable 2-Factor for.}';
|
||||
|
||||
/**
|
||||
* DisableTwoFactorCommand constructor.
|
||||
*
|
||||
* @param \Pterodactyl\Contracts\Repository\UserRepositoryInterface $repository
|
||||
*/
|
||||
public function __construct(UserRepositoryInterface $repository)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->repository = $repository;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle command execution process.
|
||||
*
|
||||
* @throws \App\Exceptions\Model\DataValidationException
|
||||
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
|
||||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||
*/
|
||||
public function handle(): void
|
||||
public function handle()
|
||||
{
|
||||
if ($this->input->isInteractive()) {
|
||||
$this->output->warning(trans('command/messages.user.2fa_help_text'));
|
||||
}
|
||||
|
||||
$email = $this->option('email') ?? $this->ask(trans('command/messages.user.ask_email'));
|
||||
$user = $this->repository->setColumns(['id', 'email'])->findFirstWhere([['email', '=', $email]]);
|
||||
|
||||
$user = User::query()->where('email', $email)->firstOrFail();
|
||||
$user->use_totp = false;
|
||||
$user->totp_secret = null;
|
||||
$user->save();
|
||||
|
||||
$this->repository->withoutFreshModel()->update($user->id, [
|
||||
'use_totp' => false,
|
||||
'totp_secret' => null,
|
||||
]);
|
||||
$this->info(trans('command/messages.user.2fa_disabled', ['email' => $user->email]));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,60 +1,73 @@
|
||||
<?php
|
||||
/**
|
||||
* Pterodactyl - Panel
|
||||
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
|
||||
*
|
||||
* This software is licensed under the terms of the MIT license.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
namespace App\Console\Commands\User;
|
||||
namespace Pterodactyl\Console\Commands\User;
|
||||
|
||||
use Exception;
|
||||
use Illuminate\Console\Command;
|
||||
use App\Services\Users\UserCreationService;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Pterodactyl\Services\Users\UserCreationService;
|
||||
|
||||
class MakeUserCommand extends Command
|
||||
{
|
||||
/**
|
||||
* @var \Pterodactyl\Services\Users\UserCreationService
|
||||
*/
|
||||
protected $creationService;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Creates a user on the system via the CLI.';
|
||||
|
||||
protected $signature = 'p:user:make {--email=} {--username=} {--password=} {--admin=} {--no-password}';
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'p:user:make {--email=} {--username=} {--name-first=} {--name-last=} {--password=} {--admin=} {--no-password}';
|
||||
|
||||
/**
|
||||
* MakeUserCommand constructor.
|
||||
*
|
||||
* @param \Pterodactyl\Services\Users\UserCreationService $creationService
|
||||
*/
|
||||
public function __construct(private UserCreationService $creationService)
|
||||
public function __construct(UserCreationService $creationService)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->creationService = $creationService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle command request to create a new user.
|
||||
*
|
||||
* @throws Exception
|
||||
* @throws \App\Exceptions\Model\DataValidationException
|
||||
* @throws \Exception
|
||||
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
|
||||
*/
|
||||
public function handle(): int
|
||||
public function handle()
|
||||
{
|
||||
try {
|
||||
DB::connection()->getPdo();
|
||||
} catch (Exception $exception) {
|
||||
$this->error($exception->getMessage());
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
$root_admin = $this->option('admin') ?? $this->confirm(trans('command/messages.user.ask_admin'));
|
||||
$email = $this->option('email') ?? $this->ask(trans('command/messages.user.ask_email'));
|
||||
$username = $this->option('username') ?? $this->ask(trans('command/messages.user.ask_username'));
|
||||
$name_first = $this->option('name-first') ?? $this->ask(trans('command/messages.user.ask_name_first'));
|
||||
$name_last = $this->option('name-last') ?? $this->ask(trans('command/messages.user.ask_name_last'));
|
||||
|
||||
if (is_null($password = $this->option('password')) && !$this->option('no-password')) {
|
||||
if (is_null($password = $this->option('password')) && ! $this->option('no-password')) {
|
||||
$this->warn(trans('command/messages.user.ask_password_help'));
|
||||
$this->line(trans('command/messages.user.ask_password_tip'));
|
||||
$password = $this->secret(trans('command/messages.user.ask_password'));
|
||||
}
|
||||
|
||||
$user = $this->creationService->handle(compact('email', 'username', 'password', 'root_admin'));
|
||||
$user = $this->creationService->handle(compact('email', 'username', 'name_first', 'name_last', 'password', 'root_admin'));
|
||||
$this->table(['Field', 'Value'], [
|
||||
['UUID', $user->uuid],
|
||||
['Email', $user->email],
|
||||
['Username', $user->username],
|
||||
['Admin', $user->isRootAdmin() ? 'Yes' : 'No'],
|
||||
['Name', $user->name],
|
||||
['Admin', $user->root_admin ? 'Yes' : 'No'],
|
||||
]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console;
|
||||
namespace Pterodactyl\Console;
|
||||
|
||||
use App\Console\Commands\Egg\CheckEggUpdatesCommand;
|
||||
use App\Console\Commands\Maintenance\CleanServiceBackupFilesCommand;
|
||||
use App\Console\Commands\Maintenance\PruneImagesCommand;
|
||||
use App\Console\Commands\Maintenance\PruneOrphanedBackupsCommand;
|
||||
use App\Console\Commands\Schedule\ProcessRunnableCommand;
|
||||
use App\Jobs\NodeStatistics;
|
||||
use App\Models\ActivityLog;
|
||||
use Illuminate\Console\Scheduling\Schedule;
|
||||
use Illuminate\Database\Console\PruneCommand;
|
||||
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
|
||||
|
||||
class Kernel extends ConsoleKernel
|
||||
@@ -18,35 +10,19 @@ class Kernel extends ConsoleKernel
|
||||
/**
|
||||
* Register the commands for the application.
|
||||
*/
|
||||
protected function commands(): void
|
||||
protected function commands()
|
||||
{
|
||||
$this->load(__DIR__ . '/Commands');
|
||||
}
|
||||
|
||||
/**
|
||||
* Define the application's command schedule.
|
||||
*
|
||||
* @param \Illuminate\Console\Scheduling\Schedule $schedule
|
||||
*/
|
||||
protected function schedule(Schedule $schedule): void
|
||||
protected function schedule(Schedule $schedule)
|
||||
{
|
||||
// https://laravel.com/docs/10.x/upgrade#redis-cache-tags
|
||||
$schedule->command('cache:prune-stale-tags')->hourly();
|
||||
|
||||
// Execute scheduled commands for servers every minute, as if there was a normal cron running.
|
||||
$schedule->command(ProcessRunnableCommand::class)->everyMinute()->withoutOverlapping();
|
||||
|
||||
$schedule->command(CleanServiceBackupFilesCommand::class)->daily();
|
||||
$schedule->command(PruneImagesCommand::class)->daily();
|
||||
$schedule->command(CheckEggUpdatesCommand::class)->hourly();
|
||||
|
||||
$schedule->job(new NodeStatistics())->everyFiveSeconds()->withoutOverlapping();
|
||||
|
||||
if (config('backups.prune_age')) {
|
||||
// Every 30 minutes, run the backup pruning command so that any abandoned backups can be deleted.
|
||||
$schedule->command(PruneOrphanedBackupsCommand::class)->everyThirtyMinutes();
|
||||
}
|
||||
|
||||
if (config('activity.prune_days')) {
|
||||
$schedule->command(PruneCommand::class, ['--model' => [ActivityLog::class]])->daily();
|
||||
}
|
||||
$schedule->command('p:schedule:process')->everyMinute()->withoutOverlapping();
|
||||
$schedule->command('p:maintenance:clean-service-backups')->daily();
|
||||
}
|
||||
}
|
||||
|
||||
15
app/Contracts/Core/ReceivesEvents.php
Normal file
15
app/Contracts/Core/ReceivesEvents.php
Normal file
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
namespace Pterodactyl\Contracts\Core;
|
||||
|
||||
use Pterodactyl\Events\Event;
|
||||
|
||||
interface ReceivesEvents
|
||||
{
|
||||
/**
|
||||
* Handles receiving an event from the application.
|
||||
*
|
||||
* @param \Pterodactyl\Events\Event $notification
|
||||
*/
|
||||
public function handle(Event $notification): void;
|
||||
}
|
||||
24
app/Contracts/Criteria/CriteriaInterface.php
Normal file
24
app/Contracts/Criteria/CriteriaInterface.php
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
/**
|
||||
* Pterodactyl - Panel
|
||||
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
|
||||
*
|
||||
* This software is licensed under the terms of the MIT license.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
namespace Pterodactyl\Contracts\Criteria;
|
||||
|
||||
use Pterodactyl\Repositories\Repository;
|
||||
|
||||
interface CriteriaInterface
|
||||
{
|
||||
/**
|
||||
* Apply selected criteria to a repository call.
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Model $model
|
||||
* @param \Pterodactyl\Repositories\Repository $repository
|
||||
* @return mixed
|
||||
*/
|
||||
public function apply($model, Repository $repository);
|
||||
}
|
||||
26
app/Contracts/Extensions/HashidsInterface.php
Normal file
26
app/Contracts/Extensions/HashidsInterface.php
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
/**
|
||||
* Pterodactyl - Panel
|
||||
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
|
||||
*
|
||||
* This software is licensed under the terms of the MIT license.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
namespace Pterodactyl\Contracts\Extensions;
|
||||
|
||||
use Hashids\HashidsInterface as VendorHashidsInterface;
|
||||
|
||||
interface HashidsInterface extends VendorHashidsInterface
|
||||
{
|
||||
/**
|
||||
* Decode an encoded hashid and return the first result.
|
||||
*
|
||||
* @param string $encoded
|
||||
* @param null $default
|
||||
* @return mixed
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function decodeFirst($encoded, $default = null);
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Contracts\Http;
|
||||
|
||||
interface ClientPermissionsRequest
|
||||
{
|
||||
/**
|
||||
* Returns the permissions string indicating which permission should be used to
|
||||
* validate that the authenticated user has permission to perform this action against
|
||||
* the given resource (server).
|
||||
*/
|
||||
public function permission(): string;
|
||||
}
|
||||
83
app/Contracts/Repository/AllocationRepositoryInterface.php
Normal file
83
app/Contracts/Repository/AllocationRepositoryInterface.php
Normal file
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
|
||||
namespace Pterodactyl\Contracts\Repository;
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
|
||||
|
||||
interface AllocationRepositoryInterface extends RepositoryInterface
|
||||
{
|
||||
/**
|
||||
* Set an array of allocation IDs to be assigned to a specific server.
|
||||
*
|
||||
* @param int|null $server
|
||||
* @param array $ids
|
||||
* @return int
|
||||
*/
|
||||
public function assignAllocationsToServer(int $server = null, array $ids): int;
|
||||
|
||||
/**
|
||||
* Return all of the allocations for a specific node.
|
||||
*
|
||||
* @param int $node
|
||||
* @return \Illuminate\Support\Collection
|
||||
*/
|
||||
public function getAllocationsForNode(int $node): Collection;
|
||||
|
||||
/**
|
||||
* Return all of the allocations for a node in a paginated format.
|
||||
*
|
||||
* @param int $node
|
||||
* @param int $perPage
|
||||
* @return \Illuminate\Contracts\Pagination\LengthAwarePaginator
|
||||
*/
|
||||
public function getPaginatedAllocationsForNode(int $node, int $perPage = 100): LengthAwarePaginator;
|
||||
|
||||
/**
|
||||
* Return all of the unique IPs that exist for a given node.
|
||||
*
|
||||
* @param int $node
|
||||
* @return \Illuminate\Support\Collection
|
||||
*/
|
||||
public function getUniqueAllocationIpsForNode(int $node): Collection;
|
||||
|
||||
/**
|
||||
* Return all of the allocations that exist for a node that are not currently
|
||||
* allocated.
|
||||
*
|
||||
* @param int $node
|
||||
* @return array
|
||||
*/
|
||||
public function getUnassignedAllocationIds(int $node): array;
|
||||
|
||||
/**
|
||||
* Get an array of all allocations that are currently assigned to a given server.
|
||||
*
|
||||
* @param int $server
|
||||
* @return array
|
||||
*/
|
||||
public function getAssignedAllocationIds(int $server): array;
|
||||
|
||||
/**
|
||||
* Return a concatenated result set of node ips that already have at least one
|
||||
* server assigned to that IP. This allows for filtering out sets for
|
||||
* dedicated allocation IPs.
|
||||
*
|
||||
* If an array of nodes is passed the results will be limited to allocations
|
||||
* in those nodes.
|
||||
*
|
||||
* @param array $nodes
|
||||
* @return array
|
||||
*/
|
||||
public function getDiscardableDedicatedAllocations(array $nodes = []): array;
|
||||
|
||||
/**
|
||||
* Return a single allocation from those meeting the requirements.
|
||||
*
|
||||
* @param array $nodes
|
||||
* @param array $ports
|
||||
* @param bool $dedicated
|
||||
* @return \Pterodactyl\Models\Allocation|null
|
||||
*/
|
||||
public function getRandomAllocation(array $nodes, array $ports, bool $dedicated = false);
|
||||
}
|
||||
43
app/Contracts/Repository/ApiKeyRepositoryInterface.php
Normal file
43
app/Contracts/Repository/ApiKeyRepositoryInterface.php
Normal file
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace Pterodactyl\Contracts\Repository;
|
||||
|
||||
use Pterodactyl\Models\User;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
interface ApiKeyRepositoryInterface extends RepositoryInterface
|
||||
{
|
||||
/**
|
||||
* Get all of the account API keys that exist for a specific user.
|
||||
*
|
||||
* @param \Pterodactyl\Models\User $user
|
||||
* @return \Illuminate\Support\Collection
|
||||
*/
|
||||
public function getAccountKeys(User $user): Collection;
|
||||
|
||||
/**
|
||||
* Get all of the application API keys that exist for a specific user.
|
||||
*
|
||||
* @param \Pterodactyl\Models\User $user
|
||||
* @return \Illuminate\Support\Collection
|
||||
*/
|
||||
public function getApplicationKeys(User $user): Collection;
|
||||
|
||||
/**
|
||||
* Delete an account API key from the panel for a specific user.
|
||||
*
|
||||
* @param \Pterodactyl\Models\User $user
|
||||
* @param string $identifier
|
||||
* @return int
|
||||
*/
|
||||
public function deleteAccountKey(User $user, string $identifier): int;
|
||||
|
||||
/**
|
||||
* Delete an application API key from the panel for a specific user.
|
||||
*
|
||||
* @param \Pterodactyl\Models\User $user
|
||||
* @param string $identifier
|
||||
* @return int
|
||||
*/
|
||||
public function deleteApplicationKey(User $user, string $identifier): int;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
/**
|
||||
* Pterodactyl - Panel
|
||||
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
|
||||
*
|
||||
* This software is licensed under the terms of the MIT license.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
namespace Pterodactyl\Contracts\Repository;
|
||||
|
||||
interface ApiPermissionRepositoryInterface extends RepositoryInterface
|
||||
{
|
||||
}
|
||||
38
app/Contracts/Repository/Attributes/SearchableInterface.php
Normal file
38
app/Contracts/Repository/Attributes/SearchableInterface.php
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace Pterodactyl\Contracts\Repository\Attributes;
|
||||
|
||||
interface SearchableInterface
|
||||
{
|
||||
/**
|
||||
* Set the search term.
|
||||
*
|
||||
* @param string|null $term
|
||||
* @return $this
|
||||
* @deprecated
|
||||
*/
|
||||
public function search($term);
|
||||
|
||||
/**
|
||||
* Set the search term to use when requesting all records from
|
||||
* the model.
|
||||
*
|
||||
* @param string|null $term
|
||||
* @return $this
|
||||
*/
|
||||
public function setSearchTerm(string $term = null);
|
||||
|
||||
/**
|
||||
* Determine if a valid search term is set on this repository.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasSearchTerm(): bool;
|
||||
|
||||
/**
|
||||
* Return the search term.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getSearchTerm();
|
||||
}
|
||||
65
app/Contracts/Repository/Daemon/BaseRepositoryInterface.php
Normal file
65
app/Contracts/Repository/Daemon/BaseRepositoryInterface.php
Normal file
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace Pterodactyl\Contracts\Repository\Daemon;
|
||||
|
||||
use GuzzleHttp\Client;
|
||||
use Pterodactyl\Models\Node;
|
||||
use Pterodactyl\Models\Server;
|
||||
|
||||
interface BaseRepositoryInterface
|
||||
{
|
||||
/**
|
||||
* Set the node model to be used for this daemon connection.
|
||||
*
|
||||
* @param \Pterodactyl\Models\Node $node
|
||||
* @return $this
|
||||
*/
|
||||
public function setNode(Node $node);
|
||||
|
||||
/**
|
||||
* Return the node model being used.
|
||||
*
|
||||
* @return \Pterodactyl\Models\Node|null
|
||||
*/
|
||||
public function getNode();
|
||||
|
||||
/**
|
||||
* Set the Server model to use when requesting information from the Daemon.
|
||||
*
|
||||
* @param \Pterodactyl\Models\Server $server
|
||||
* @return $this
|
||||
*/
|
||||
public function setServer(Server $server);
|
||||
|
||||
/**
|
||||
* Return the Server model.
|
||||
*
|
||||
* @return \Pterodactyl\Models\Server|null
|
||||
*/
|
||||
public function getServer();
|
||||
|
||||
/**
|
||||
* Set the token to be used in the X-Access-Token header for requests to the daemon.
|
||||
*
|
||||
* @param string $token
|
||||
* @return $this
|
||||
*/
|
||||
public function setToken(string $token);
|
||||
|
||||
/**
|
||||
* Return the access token being used for requests.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getToken();
|
||||
|
||||
/**
|
||||
* Return an instance of the Guzzle HTTP Client to be used for requests.
|
||||
*
|
||||
* @param array $headers
|
||||
* @return \GuzzleHttp\Client
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||
*/
|
||||
public function getHttpClient(array $headers = []): Client;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace Pterodactyl\Contracts\Repository\Daemon;
|
||||
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
interface CommandRepositoryInterface extends BaseRepositoryInterface
|
||||
{
|
||||
/**
|
||||
* Send a command to a server.
|
||||
*
|
||||
* @param string $command
|
||||
* @return \Psr\Http\Message\ResponseInterface
|
||||
*/
|
||||
public function send(string $command): ResponseInterface;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace Pterodactyl\Contracts\Repository\Daemon;
|
||||
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
interface ConfigurationRepositoryInterface extends BaseRepositoryInterface
|
||||
{
|
||||
/**
|
||||
* Update the configuration details for the specified node using data from the database.
|
||||
*
|
||||
* @param array $overrides
|
||||
* @return \Psr\Http\Message\ResponseInterface
|
||||
*/
|
||||
public function update(array $overrides = []): ResponseInterface;
|
||||
}
|
||||
50
app/Contracts/Repository/Daemon/FileRepositoryInterface.php
Normal file
50
app/Contracts/Repository/Daemon/FileRepositoryInterface.php
Normal file
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace Pterodactyl\Contracts\Repository\Daemon;
|
||||
|
||||
use stdClass;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
interface FileRepositoryInterface extends BaseRepositoryInterface
|
||||
{
|
||||
/**
|
||||
* Return stat information for a given file.
|
||||
*
|
||||
* @param string $path
|
||||
* @return \stdClass
|
||||
*
|
||||
* @throws \GuzzleHttp\Exception\RequestException
|
||||
*/
|
||||
public function getFileStat(string $path): stdClass;
|
||||
|
||||
/**
|
||||
* Return the contents of a given file if it can be edited in the Panel.
|
||||
*
|
||||
* @param string $path
|
||||
* @return string
|
||||
*
|
||||
* @throws \GuzzleHttp\Exception\RequestException
|
||||
*/
|
||||
public function getContent(string $path): string;
|
||||
|
||||
/**
|
||||
* Save new contents to a given file.
|
||||
*
|
||||
* @param string $path
|
||||
* @param string $content
|
||||
* @return \Psr\Http\Message\ResponseInterface
|
||||
*
|
||||
* @throws \GuzzleHttp\Exception\RequestException
|
||||
*/
|
||||
public function putContent(string $path, string $content): ResponseInterface;
|
||||
|
||||
/**
|
||||
* Return a directory listing for a given path.
|
||||
*
|
||||
* @param string $path
|
||||
* @return array
|
||||
*
|
||||
* @throws \GuzzleHttp\Exception\RequestException
|
||||
*/
|
||||
public function getDirectory(string $path): array;
|
||||
}
|
||||
23
app/Contracts/Repository/Daemon/PowerRepositoryInterface.php
Normal file
23
app/Contracts/Repository/Daemon/PowerRepositoryInterface.php
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace Pterodactyl\Contracts\Repository\Daemon;
|
||||
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
interface PowerRepositoryInterface extends BaseRepositoryInterface
|
||||
{
|
||||
const SIGNAL_START = 'start';
|
||||
const SIGNAL_STOP = 'stop';
|
||||
const SIGNAL_RESTART = 'restart';
|
||||
const SIGNAL_KILL = 'kill';
|
||||
|
||||
/**
|
||||
* Send a power signal to a server.
|
||||
*
|
||||
* @param string $signal
|
||||
* @return \Psr\Http\Message\ResponseInterface
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\Repository\Daemon\InvalidPowerSignalException
|
||||
*/
|
||||
public function sendSignal(string $signal): ResponseInterface;
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
|
||||
namespace Pterodactyl\Contracts\Repository\Daemon;
|
||||
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
interface ServerRepositoryInterface extends BaseRepositoryInterface
|
||||
{
|
||||
/**
|
||||
* Create a new server on the daemon for the panel.
|
||||
*
|
||||
* @param array $structure
|
||||
* @param array $overrides
|
||||
* @return \Psr\Http\Message\ResponseInterface
|
||||
*
|
||||
* @throws \GuzzleHttp\Exception\RequestException
|
||||
*/
|
||||
public function create(array $structure, array $overrides = []): ResponseInterface;
|
||||
|
||||
/**
|
||||
* Update server details on the daemon.
|
||||
*
|
||||
* @param array $data
|
||||
* @return \Psr\Http\Message\ResponseInterface
|
||||
*/
|
||||
public function update(array $data): ResponseInterface;
|
||||
|
||||
/**
|
||||
* Mark a server to be reinstalled on the system.
|
||||
*
|
||||
* @param array|null $data
|
||||
* @return \Psr\Http\Message\ResponseInterface
|
||||
*/
|
||||
public function reinstall(array $data = null): ResponseInterface;
|
||||
|
||||
/**
|
||||
* Mark a server as needing a container rebuild the next time the server is booted.
|
||||
*
|
||||
* @return \Psr\Http\Message\ResponseInterface
|
||||
*/
|
||||
public function rebuild(): ResponseInterface;
|
||||
|
||||
/**
|
||||
* Suspend a server on the daemon.
|
||||
*
|
||||
* @return \Psr\Http\Message\ResponseInterface
|
||||
*/
|
||||
public function suspend(): ResponseInterface;
|
||||
|
||||
/**
|
||||
* Un-suspend a server on the daemon.
|
||||
*
|
||||
* @return \Psr\Http\Message\ResponseInterface
|
||||
*/
|
||||
public function unsuspend(): ResponseInterface;
|
||||
|
||||
/**
|
||||
* Delete a server on the daemon.
|
||||
*
|
||||
* @return \Psr\Http\Message\ResponseInterface
|
||||
*/
|
||||
public function delete(): ResponseInterface;
|
||||
|
||||
/**
|
||||
* Return details on a specific server.
|
||||
*
|
||||
* @return \Psr\Http\Message\ResponseInterface
|
||||
*/
|
||||
public function details(): ResponseInterface;
|
||||
|
||||
/**
|
||||
* Revoke an access key on the daemon before the time is expired.
|
||||
*
|
||||
* @param string|array $key
|
||||
* @return \Psr\Http\Message\ResponseInterface
|
||||
*
|
||||
* @throws \GuzzleHttp\Exception\RequestException
|
||||
*/
|
||||
public function revokeAccessKey($key): ResponseInterface;
|
||||
}
|
||||
52
app/Contracts/Repository/DaemonKeyRepositoryInterface.php
Normal file
52
app/Contracts/Repository/DaemonKeyRepositoryInterface.php
Normal file
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
namespace Pterodactyl\Contracts\Repository;
|
||||
|
||||
use Pterodactyl\Models\User;
|
||||
use Pterodactyl\Models\DaemonKey;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
interface DaemonKeyRepositoryInterface extends RepositoryInterface
|
||||
{
|
||||
/**
|
||||
* String prepended to keys to identify that they are managed internally and not part of the user API.
|
||||
*/
|
||||
const INTERNAL_KEY_IDENTIFIER = 'i_';
|
||||
|
||||
/**
|
||||
* Load the server and user relations onto a key model.
|
||||
*
|
||||
* @param \Pterodactyl\Models\DaemonKey $key
|
||||
* @param bool $refresh
|
||||
* @return \Pterodactyl\Models\DaemonKey
|
||||
*/
|
||||
public function loadServerAndUserRelations(DaemonKey $key, bool $refresh = false): DaemonKey;
|
||||
|
||||
/**
|
||||
* Return a daemon key with the associated server relation attached.
|
||||
*
|
||||
* @param string $key
|
||||
* @return \Pterodactyl\Models\DaemonKey
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||
*/
|
||||
public function getKeyWithServer(string $key): DaemonKey;
|
||||
|
||||
/**
|
||||
* Get all of the keys for a specific user including the information needed
|
||||
* from their server relation for revocation on the daemon.
|
||||
*
|
||||
* @param \Pterodactyl\Models\User $user
|
||||
* @return \Illuminate\Support\Collection
|
||||
*/
|
||||
public function getKeysForRevocation(User $user): Collection;
|
||||
|
||||
/**
|
||||
* Delete an array of daemon keys from the database. Used primarily in
|
||||
* conjunction with getKeysForRevocation.
|
||||
*
|
||||
* @param array $ids
|
||||
* @return bool|int
|
||||
*/
|
||||
public function deleteKeys(array $ids);
|
||||
}
|
||||
16
app/Contracts/Repository/DatabaseHostRepositoryInterface.php
Normal file
16
app/Contracts/Repository/DatabaseHostRepositoryInterface.php
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace Pterodactyl\Contracts\Repository;
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
interface DatabaseHostRepositoryInterface extends RepositoryInterface
|
||||
{
|
||||
/**
|
||||
* Return database hosts with a count of databases and the node
|
||||
* information for which it is attached.
|
||||
*
|
||||
* @return \Illuminate\Support\Collection
|
||||
*/
|
||||
public function getWithViewDetails(): Collection;
|
||||
}
|
||||
108
app/Contracts/Repository/DatabaseRepositoryInterface.php
Normal file
108
app/Contracts/Repository/DatabaseRepositoryInterface.php
Normal file
@@ -0,0 +1,108 @@
|
||||
<?php
|
||||
|
||||
namespace Pterodactyl\Contracts\Repository;
|
||||
|
||||
use Pterodactyl\Models\Database;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
|
||||
|
||||
interface DatabaseRepositoryInterface extends RepositoryInterface
|
||||
{
|
||||
const DEFAULT_CONNECTION_NAME = 'dynamic';
|
||||
|
||||
/**
|
||||
* Set the connection name to execute statements against.
|
||||
*
|
||||
* @param string $connection
|
||||
* @return $this
|
||||
*/
|
||||
public function setConnection(string $connection);
|
||||
|
||||
/**
|
||||
* Return the connection to execute statements against.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getConnection(): string;
|
||||
|
||||
/**
|
||||
* Return all of the databases belonging to a server.
|
||||
*
|
||||
* @param int $server
|
||||
* @return \Illuminate\Support\Collection
|
||||
*/
|
||||
public function getDatabasesForServer(int $server): Collection;
|
||||
|
||||
/**
|
||||
* Return all of the databases for a given host with the server relationship loaded.
|
||||
*
|
||||
* @param int $host
|
||||
* @param int $count
|
||||
* @return \Illuminate\Contracts\Pagination\LengthAwarePaginator
|
||||
*/
|
||||
public function getDatabasesForHost(int $host, int $count = 25): LengthAwarePaginator;
|
||||
|
||||
/**
|
||||
* Create a new database if it does not already exist on the host with
|
||||
* the provided details.
|
||||
*
|
||||
* @param array $data
|
||||
* @return \Pterodactyl\Models\Database
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
|
||||
* @throws \Pterodactyl\Exceptions\Repository\DuplicateDatabaseNameException
|
||||
*/
|
||||
public function createIfNotExists(array $data): Database;
|
||||
|
||||
/**
|
||||
* Create a new database on a given connection.
|
||||
*
|
||||
* @param string $database
|
||||
* @return bool
|
||||
*/
|
||||
public function createDatabase(string $database): bool;
|
||||
|
||||
/**
|
||||
* Create a new database user on a given connection.
|
||||
*
|
||||
* @param string $username
|
||||
* @param string $remote
|
||||
* @param string $password
|
||||
* @return bool
|
||||
*/
|
||||
public function createUser(string $username, string $remote, string $password): bool;
|
||||
|
||||
/**
|
||||
* Give a specific user access to a given database.
|
||||
*
|
||||
* @param string $database
|
||||
* @param string $username
|
||||
* @param string $remote
|
||||
* @return bool
|
||||
*/
|
||||
public function assignUserToDatabase(string $database, string $username, string $remote): bool;
|
||||
|
||||
/**
|
||||
* Flush the privileges for a given connection.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function flush(): bool;
|
||||
|
||||
/**
|
||||
* Drop a given database on a specific connection.
|
||||
*
|
||||
* @param string $database
|
||||
* @return bool
|
||||
*/
|
||||
public function dropDatabase(string $database): bool;
|
||||
|
||||
/**
|
||||
* Drop a given user on a specific connection.
|
||||
*
|
||||
* @param string $username
|
||||
* @param string $remote
|
||||
* @return mixed
|
||||
*/
|
||||
public function dropUser(string $username, string $remote): bool;
|
||||
}
|
||||
61
app/Contracts/Repository/EggRepositoryInterface.php
Normal file
61
app/Contracts/Repository/EggRepositoryInterface.php
Normal file
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
/**
|
||||
* Pterodactyl - Panel
|
||||
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
|
||||
*
|
||||
* This software is licensed under the terms of the MIT license.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
namespace Pterodactyl\Contracts\Repository;
|
||||
|
||||
use Pterodactyl\Models\Egg;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
|
||||
interface EggRepositoryInterface extends RepositoryInterface
|
||||
{
|
||||
/**
|
||||
* Return an egg with the variables relation attached.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Pterodactyl\Models\Egg
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||
*/
|
||||
public function getWithVariables(int $id): Egg;
|
||||
|
||||
/**
|
||||
* Return all eggs and their relations to be used in the daemon API.
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Collection
|
||||
*/
|
||||
public function getAllWithCopyAttributes(): Collection;
|
||||
|
||||
/**
|
||||
* Return an egg with the scriptFrom and configFrom relations loaded onto the model.
|
||||
*
|
||||
* @param int|string $value
|
||||
* @param string $column
|
||||
* @return \Pterodactyl\Models\Egg
|
||||
*/
|
||||
public function getWithCopyAttributes($value, string $column = 'id'): Egg;
|
||||
|
||||
/**
|
||||
* Return all of the data needed to export a service.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Pterodactyl\Models\Egg
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||
*/
|
||||
public function getWithExportAttributes(int $id): Egg;
|
||||
|
||||
/**
|
||||
* Confirm a copy script belongs to the same nest as the item trying to use it.
|
||||
*
|
||||
* @param int $copyFromId
|
||||
* @param int $service
|
||||
* @return bool
|
||||
*/
|
||||
public function isCopyableScript(int $copyFromId, int $service): bool;
|
||||
}
|
||||
24
app/Contracts/Repository/EggVariableRepositoryInterface.php
Normal file
24
app/Contracts/Repository/EggVariableRepositoryInterface.php
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
/**
|
||||
* Pterodactyl - Panel
|
||||
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
|
||||
*
|
||||
* This software is licensed under the terms of the MIT license.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
namespace Pterodactyl\Contracts\Repository;
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
interface EggVariableRepositoryInterface extends RepositoryInterface
|
||||
{
|
||||
/**
|
||||
* Return editable variables for a given egg. Editable variables must be set to
|
||||
* user viewable in order to be picked up by this function.
|
||||
*
|
||||
* @param int $egg
|
||||
* @return \Illuminate\Support\Collection
|
||||
*/
|
||||
public function getEditableVariables(int $egg): Collection;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user