Remove old views

This commit is contained in:
Dane Everitt 2017-03-03 23:40:31 -05:00
parent b1564389d8
commit 9a14cb5687
No known key found for this signature in database
GPG key ID: EEA66103B3D71F53
11 changed files with 0 additions and 2514 deletions

View file

@ -1,58 +0,0 @@
{{-- Copyright (c) 2015 - 2017 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. --}}
@extends('layouts.admin')
@section('title')
Administration
@endsection
@section('content')
<div class="row">
<div class="col-md-12">
<ul class="breadcrumb">
<li class="active">Admin Control</li>
</ul>
<h3 class="nopad">Pterodactyl Admin Control Panel</h3><hr />
@if (Version::isLatestPanel())
<div class="alert alert-success">You are running Pterodactyl Panel version <code>{{ Version::getCurrentPanel() }}</code>. Your panel is up-to-date!</div>
@else
<div class="alert alert-danger">
Your panel is <strong>not up-to-date!</strong> The latest version is <a href="https://github.com/Pterodactyl/Panel/releases/v{{ Version::getPanel() }}" target="_blank"><code>{{ Version::getPanel() }}</code></a> and you are currently running version <code>{{ Version::getCurrentPanel() }}</code>.
</div>
@endif
</div>
</div>
<div class="row">
<div class="col-xs-4 text-center">
<a href="{{ Version::getDiscord() }}"><button class="btn btn-sm btn-warning" style="width:100%;"><i class="fa fa-fw fa-support"></i> Get Help <small>(via Discord)</small></button></a>
</div>
<div class="col-xs-4 text-center">
<a href="https://docs.pterodactyl.io"><button class="btn btn-sm btn-default" style="width:100%;"><i class="fa fa-fw fa-link"></i> Documentation</button></a>
</div>
<div class="col-xs-4 text-center">
<a href="https://github.com/Pterodactyl/Panel"><button class="btn btn-sm btn-default" style="width:100%;"><i class="fa fa-fw fa-support"></i> Github</button></a>
</div>
</div>
<script>
$(document).ready(function () {
$('#sidebar_links').find("a[href='/admin']").addClass('active');
});
</script>
@endsection

View file

@ -1,96 +0,0 @@
{{-- Copyright (c) 2015 - 2017 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. --}}
@extends('layouts.admin')
@section('title')
Node List
@endsection
@section('scripts')
@parent
{!! Theme::css('css/vendor/fontawesome/animation.min.css') !!}
@endsection
@section('content')
<div class="col-md-12">
<ul class="breadcrumb">
<li><a href="/admin">Admin Control</a></li>
<li class="active">Nodes</li>
</ul>
<h3>All Nodes</h3><hr />
<table class="table table-bordered table-hover">
<thead>
<tr>
<th></th>
<th>Name</th>
<th>Location</th>
<th class="hidden-xs">Memory</th>
<th class="hidden-xs">Disk</th>
<th class="text-center hidden-xs">Servers</th>
<th class="text-center">SSL</th>
<th class="text-center hidden-xs">Public</th>
</tr>
</thead>
<tbody>
@foreach ($nodes as $node)
<tr>
<td class="text-center text-muted left-icon" data-action="ping" data-secret="{{ $node->daemonSecret }}" data-location="{{ $node->scheme }}://{{ $node->fqdn }}:{{ $node->daemonListen }}"><i class="fa fa-fw fa-refresh fa-spin"></i></td>
<td><a href="/admin/nodes/view/{{ $node->id }}">{{ $node->name }}</td>
<td>{{ $node->location->short }}</td>
<td class="hidden-xs">{{ $node->memory }} MB</td>
<td class="hidden-xs">{{ $node->disk }} MB</td>
<td class="text-center hidden-xs">{{ $node->servers_count }}</td>
<td class="text-center" style="color:{{ ($node->scheme === 'https') ? '#50af51' : '#d9534f' }}"><i class="fa fa-{{ ($node->scheme === 'https') ? 'lock' : 'unlock' }}"></i></td>
<td class="text-center hidden-xs"><i class="fa fa-{{ ($node->public === 1) ? 'eye' : 'eye-slash' }}"></i></td>
</tr>
@endforeach
</tbody>
</table>
<div class="row">
<div class="col-md-12 text-center">{!! $nodes->render() !!}</div>
</div>
</div>
<script>
$(document).ready(function () {
$('#sidebar_links').find("a[href='/admin/nodes']").addClass('active');
(function pingNodes() {
$('td[data-action="ping"]').each(function(i, element) {
$.ajax({
type: 'GET',
url: $(element).data('location'),
headers: {
'X-Access-Token': $(element).data('secret'),
},
timeout: 5000
}).done(function (data) {
$(element).find('i').tooltip({
title: 'v' + data.version,
});
$(element).removeClass('text-muted').find('i').removeClass().addClass('fa fa-fw fa-heartbeat faa-pulse animated').css('color', '#50af51');
}).fail(function () {
$(element).removeClass('text-muted').find('i').removeClass().addClass('fa fa-fw fa-heart-o').css('color', '#d9534f');
}).always(function () {
setTimeout(pingNodes, 10000);
});
});
})();
});
</script>
@endsection

View file

@ -1,187 +0,0 @@
{{-- Copyright (c) 2015 - 2017 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. --}}
@extends('layouts.admin')
@section('title')
Create Node
@endsection
@section('content')
<div class="col-md-12">
<ul class="breadcrumb">
<li><a href="/admin">Admin Control</a></li>
<li><a href="/admin/nodes">Nodes</a></li>
<li class="active">Create New Node</li>
</ul>
<h3>Create New Node</h3><hr />
<form action="/admin/nodes/new" method="POST">
<div class="well">
<div class="row">
<div class="form-group col-md-6">
<label for="name" class="control-label">Node Name</label>
<div>
<input type="text" autocomplete="off" name="name" class="form-control" value="{{ old('name') }}" />
<p class="text-muted"><small>Character limits: <code>a-zA-Z0-9_.-</code> and <code>[Space]</code> (min 1, max 100 characters).</small></p>
</div>
</div>
<div class="form-group col-md-4">
<label for="name" class="control-label">Location</label>
<div>
<select name="location_id" class="form-control">
@foreach($locations as $location)
<option value="{{ $location->id }}" {{ (old('location_id') === $location->id) ? 'selected' : '' }}>{{ $location->long }} ({{ $location->short }})</option>
@endforeach
</select>
</div>
</div>
<div class="form-group col-md-2">
<label for="public" class="control-label">Public <sup><a data-toggle="tooltip" data-placement="top" title="Allow automatic allocation to this Node?">?</a></sup></label>
<div>
<input type="radio" name="public" value="1" {{ (old('public') === '1') ? 'checked' : '' }} id="public_1" checked> <label for="public_1" style="padding-left:5px;">Yes</label><br />
<input type="radio" name="public" value="0" {{ (old('public') === '0') ? 'checked' : '' }} id="public_0"> <label for="public_0" style="padding-left:5px;">No</label>
</div>
</div>
</div>
</div>
<div class="well">
<div class="row">
<div class="form-group col-md-6">
<label for="fqdn" class="control-label">Fully Qualified Domain Name</label>
<div>
<input type="text" autocomplete="off" name="fqdn" class="form-control" value="{{ old('fqdn') }}" />
</div>
<p class="text-muted"><small>Please enter domain name (e.g <code>node.example.com</code>) to be used for connecting to the daemon. An IP address may only be used if you are not using SSL for this node.
<a tabindex="0" data-toggle="popover" data-trigger="focus" title="Why do I need a FQDN?" data-content="In order to secure communications between your server and this node we use SSL. We cannot generate a SSL certificate for IP Addresses, and as such you will need to provide a FQDN.">Why?</a>
</small></p>
</div>
<div class="form-group col-md-6">
<label for="scheme" class="control-label">Secure Socket Layer</label>
<div class="row" style="padding: 7px 0;">
<div class="col-xs-6">
<input type="radio" name="scheme" value="https" id="scheme_ssl" checked /> <label for="scheme_ssl" style="padding-left: 5px;">Enable HTTPS/SSL</label>
</div>
<div class="col-xs-6">
<input type="radio" name="scheme" value="http" id="scheme_nossl" /> <label for="scheme_nossl" style="padding-left: 5px;">Disable HTTPS/SSL</label>
</div>
</div>
<p class="text-muted"><small>You should always leave SSL enabled for nodes. Disabling SSL could allow a malicious user to intercept traffic between the panel and the daemon potentially exposing sensitive information.</small></p>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="well">
<div class="row">
<div class="form-group col-md-6 col-xs-6">
<label for="memory" class="control-label">Total Memory</label>
<div class="input-group">
<input type="text" name="memory" data-multiplicator="true" class="form-control" value="{{ old('memory') }}"/>
<span class="input-group-addon">MB</span>
</div>
</div>
<div class="form-group col-md-6 col-xs-6">
<label for="memory_overallocate" class="control-label">Overallocate</label>
<div class="input-group">
<input type="text" name="memory_overallocate" class="form-control" value="{{ old('memory_overallocate', 0) }}"/>
<span class="input-group-addon">%</span>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<p class="text-muted"><small>Enter the total amount of memory avaliable for new servers. If you would like to allow overallocation of memory enter the percentage that you want to allow. To disable checking for overallocation enter <code>-1</code> into the field. Entering <code>0</code> will prevent creating new servers if it would put the node over the limit.</small></p>
</div>
</div>
</div>
</div>
<div class="col-md-6">
<div class="well">
<div class="row">
<div class="form-group col-md-6 col-xs-6">
<label for="disk" class="control-label">Disk Space</label>
<div class="input-group">
<input type="text" name="disk" data-multiplicator="true" class="form-control" value="{{ old('disk') }}"/>
<span class="input-group-addon">MB</span>
</div>
</div>
<div class="form-group col-md-6 col-xs-6">
<label for="disk_overallocate" class="control-label">Overallocate</label>
<div class="input-group">
<input type="text" name="disk_overallocate" class="form-control" value="{{ old('disk_overallocate', 0) }}"/>
<span class="input-group-addon">%</span>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<p class="text-muted"><small>Enter the total amount of disk space avaliable for new servers. If you would like to allow overallocation of disk space enter the percentage that you want to allow. To disable checking for overallocation enter <code>-1</code> into the field. Entering <code>0</code> will prevent creating new servers if it would put the node over the limit.</small></p>
</div>
</div>
</div>
</div>
</div>
<div class="well">
<div class="row">
<div class="form-group col-md-6">
<label for="daemonBase" class="control-label">Daemon Server File Location</label>
<div>
<input type="text" name="daemonBase" class="form-control" value="{{ old('daemonBase', '/srv/daemon-data') }}"/>
</div>
<p class="text-muted"><small>The location at which your server files will be stored. Most users do not need to change this.</small></p>
</div>
<div class="form-group col-md-6">
<div class="row">
<div class="form-group col-md-6">
<label for="daemonListen" class="control-label">Daemon Listening Port</label>
<div>
<input type="text" name="daemonListen" class="form-control" value="{{ old('daemonListen', '8080') }}"/>
</div>
</div>
<div class="form-group col-md-6">
<label for="daemonSFTP" class="control-label">Daemon SFTP Port</label>
<div>
<input type="text" name="daemonSFTP" class="form-control" value="{{ old('daemonSFTP', '2022') }}"/>
</div>
</div>
</div>
<p class="text-muted"><small>The daemon runs its own SFTP management container and does not use the SSHd process on the main physical server. <Strong>Do not use the same port that you have assigned for your physcial server's SSH process.</strong></small></p>
</div>
</div>
</div>
<div class="well">
<div class="row">
<div class="col-md-12">
{!! csrf_field() !!}
<input type="submit" class="btn btn-sm btn-primary" value="Create Node" />
</div>
</div>
</div>
</form>
</div>
<script>
$(document).ready(function () {
$('#sidebar_links').find("a[href='/admin/nodes/new']").addClass('active');
$('[data-toggle="popover"]').popover({
placement: 'auto'
});
$('[data-toggle="tooltip"]').tooltip();
});
</script>
@endsection

View file

@ -1,292 +0,0 @@
#!/bin/bash
####
# Pterodactyl - Panel
# Copyright (c) 2015 - 2017 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.
####
set +e
export DEBIAN_FRONTEND=noninteractive
INSTALL_DIR="/srv/daemon"
DATA_DIR="{{ $node->daemonBase }}"
CURRENT_SYSTEM_KERNEL="$(uname -r)"
DL_VERSION="0.0.1"
command_exists() {
command -v "$@" > /dev/null 2>&1
}
error_message() {
echo -e "\e[1m\e[97m\e[41m$1\e[0m"
exit 1
}
warning_message() {
echo -e "\e[43m\e[30m$1\e[0m"
}
success_message() {
echo -e "\e[32m$1\e[0m"
}
running_command() {
echo -e " ;; \e[47m\e[30m$1\e[0m"
}
for i in "$@"
do
case $i in
-d|--directory)
INSTALL_DIR="$2"
;;
-a|--datadir)
DATA_DIR="$2"
;;
-g|--git)
USE_GIT=true
;;
-u|--unstable)
USE_UNSTABLE=true
USE_GIT=true
;;
-v|--version)
DL_VERSION="$2"
;;
-h|--help)
echo "./installer [opts]"
echo " -d | --directory The directory to install the daemon into. (default: /srv/daemon)"
echo " -a | --datadir The directory that daemon users will be stored in. (default: /srv/daemon-data)"
echo " -g | --git Use this flag to download the daemon using a git clone. (default: false)"
echo " -u | --unstable Install unstable version of the daemon, automatically uses --git flag. (default: false)"
echo " -v | --version The version of the daemon to download."
exit
;;
esac
shift
done
warning_message "This program will automatically configure your system to run the Pterodactyl Daemon."
warning_message " - Install Location: $INSTALL_DIR"
warning_message " - Data Location: $DATA_DIR"
warning_message "This script will continue in 10 seconds. Press CRTL+C to exit now."
sleep 10
# Super basic system detection
if command_exists apt-get; then
INSTALL_CMD="apt-get -y"
elif command_exists yum; then
INSTALL_CMD="yum -y"
else
error_message "No supported repository manager was found."
fi
if ! command_exists curl; then
warning_message "No file retrieval method found, installing curl now..."
running_command "$INSTALL_CMD -y install curl"
$INSTALL_CMD -y install curl
if [ "$?" -ne "0" ]; then
error_message "Unable to install curl and no other method was found for retrieving files."
fi
fi
# Determine if the kernel is high enough version.
if command_exists awk; then
PROCESSED_KERNEL_VERSION=$(awk -F. '{print $1$2}' <<< $CURRENT_SYSTEM_KERNEL)
elif command_exists cut; then
PROCESSED_KERNEL_VERSION=$(cut -d. -f1-2 --output-delimiter='' <<< $CURRENT_SYSTEM_KERNEL)
else
error_message "You seem to be missing some core tools that this script needs: awk (or) cut"
fi
if [ "$PROCESSED_KERNEL_VERSION" -lt "310" ]; then
error_message "Your kernel version must be at least 3.10 or higher for the daemon to work. You are using $CURRENT_SYSTEM_KERNEL"
fi
check_cgroups() {
# Check CGroups
CGROUP_DIRECTORY_LISTING="$(awk '/[, ](cpu|cpuacct|cpuset|devices|freezer|memory)[, ]/ && $3 == "cgroup" { print $2 }' /proc/mounts | head -n1)"
if [ ! -z $CGROUP_DIRECTORY_LISTING -a -d $CGROUP_DIRECTORY_LISTING ]; then
CGROUP_DIRECTORY="$(dirname $CGROUP_DIRECTORY_LISTING 2>&1)"
if [ -d "$CGROUP_DIRECTORY/cpu" -a -d "$CGROUP_DIRECTORY/cpuacct" -a -d "$CGROUP_DIRECTORY/cpuset" -a -d "$CGROUP_DIRECTORY/devices" -a -d "$CGROUP_DIRECTORY/freezer" -a -d "$CGROUP_DIRECTORY/memory" ]; then
success_message "cgroups enabled and are valid on this machine."
else
error_message "You appear to be missing some important cgroups on this machine."
fi
else
if [ ! -e "/proc/cgroups" ]; then
error_message "This kernel does not appear to support cgroups! Please see https://gist.github.com/DaneEveritt/0f071f481b4d3fa637d4 for more information."
elif [ ! -d "/sys/fs/cgroup" ]; then
error_message "This kernel does not appear to support cgroups! Please see https://gist.github.com/DaneEveritt/0f071f481b4d3fa637d4 for more information."
fi
if [ ! -f "/tmp/mount_cgroup.sh" ]; then
# Try to enable cgroups
warning_message "Attempting to enable cgroups on this machine..."
running_command "curl -L https://raw.githubusercontent.com/tianon/cgroupfs-mount/master/cgroupfs-mount > /tmp/mount_cgroup.sh"
curl -L https://raw.githubusercontent.com/tianon/cgroupfs-mount/master/cgroupfs-mount > /tmp/mount_cgroup.sh
running_command "chmod +x /tmp/mount_cgroup.sh"
chmod +x /tmp/mount_cgroup.sh
running_command "bash /tmp/mount_cgroup.sh"
bash /tmp/mount_cgroup.sh
check_cgroups
else
rm -rf /tmp/mount_cgroup.sh > /dev/null 2>&1
error_message "Failed to enable cgroups on this machine."
fi
fi
}
# Check those groups.
check_cgroups
# Lets install the dependencies.
$INSTALL_CMD install linux-image-extra-$CURRENT_SYSTEM_KERNEL
if [ "$?" -ne "0" ]; then
warning_message "You appear to have a non-generic kernel meaning we could not install extra kernel tools."
warning_message "We will continue to install, but some docker enhancements might not work as expected."
warning_message "Continuing in 10 seconds, press CTRL+C to cancel this script."
sleep 10
fi
success_message "Installing Docker..."
running_command "curl -L https://get.docker.com/ | sh"
curl -L https://get.docker.com/ | sh
if [ "$?" -ne "0" ]; then
error_message "Unable to install docker, an error occured!"
fi;
success_message "Installing NodeJS 5.x..."
running_command "curl -L https://deb.nodesource.com/setup_5.x | sudo -E bash -"
curl -L https://deb.nodesource.com/setup_5.x | sudo -E bash -
if [ "$?" -ne "0" ]; then
error_message "Unable to configure NodeJS, an error occured!"
fi;
running_command "$INSTALL_CMD install tar nodejs"
$INSTALL_CMD install tar nodejs
if [ "$?" -ne "0" ]; then
error_message "Unable to install NodeJS or Tar, an error occured!"
fi;
running_command "mkdir -p $INSTALL_DIR $DATA_DIR"
mkdir -p $INSTALL_DIR $DATA_DIR
cd $INSTALL_DIR
if [ -z $USE_UNSTABLE -a -z $USE_GIT ]; then
CLEANUP_PROGRAMS="nodejs docker-engine"
running_command "curl -sI https://github.com/Pterodactyl/Daemon/archive/$DL_VERSION.tar.gz | head -n1 | cut -d$' ' -f2"
GITHUB_STATUS="$(curl -sI https://github.com/Pterodactyl/Daemon/archive/$DL_VERSION.tar.gz | head -n1 | cut -d$' ' -f2)"
if [ $GITHUB_STATUS -ne "200" ]; then
$INSTALL_CMD remove $CLEANUP_PROGRAMS 2>&1
error_message "Github returned a non-200 response code ($GITHUB_STATUS)"
fi
running_command "curl -L \"https://github.com/Pterodactyl/Daemon/archive/$DL_VERSION.tar.gz\" > daemon.tar.gz"
curl -L "https://github.com/Pterodactyl/Daemon/archive/$DL_VERSION.tar.gz" > daemon.tar.gz
running_command "tar --strip-components=1 -xzvf daemon.tar.gz"
tar --strip-components=1 -xzvf daemon.tar.gz 2>&1
if [ "$?" -ne "0" ]; then
$INSTALL_CMD remove $CLEANUP_PROGRAMS 2>&1
cd ~ && rm -rf $INSTALL_DIR 2>&1
error_message "Unable to install the daemon due to an error while attempting to unpack files."
fi
elif [ $USE_GIT ]; then
CLEANUP_PROGRAMS="nodejs docker-engine git"
running_command "$INSTALL_CMD install git"
$INSTALL_CMD install git
running_command "git clone https://github.com/Pterodactyl/Daemon.git ."
git clone https://github.com/Pterodactyl/Daemon.git .
if [ -z $USE_UNSTABLE ]; then
running_command "git checkout tags/$DL_VERSION"
git checkout tags/$DL_VERSION
fi
if [ "$?" -ne "0" ]; then
$INSTALL_CMD remove $CLEANUP_PROGRAMS 2>&1
cd ~ && rm -rf $INSTALL_DIR 2>&1
error_message "Unable to install the daemon due to an error while attempting to clone files to the server."
fi
else
error_message "Could not match an install method!"
fi
running_command "npm install --production"
npm install --production
if [ "$?" -ne "0" ]; then
$INSTALL_CMD remove $CLEANUP_PROGRAMS 2>&1
cd ~ && rm -rf $INSTALL_DIR 2>&1
error_message "Unable to install the daemon due to an error that occured while running npm install."
fi
running_command "docker run -d --name ptdl-sftp -p 2022:22 -v $DATA_DIR:/sftp-root -v $INSTALL_DIR/config/credentials:/creds quay.io/pterodactyl/scrappy"
docker run -d --name ptdl-sftp -p 2022:22 -v $DATA_DIR:/sftp-root -v $INSTALL_DIR/config/credentials:/creds quay.io/pterodactyl/scrappy
if [ "$?" -ne "0" ]; then
$INSTALL_CMD remove $CLEANUP_PROGRAMS 2>&1
cd ~ && rm -rf $INSTALL_DIR 2>&1
error_message "Unable to install the daemon due to an error while creating a SFTP container."
fi
echo '{
"web": {
"listen": {{ $node->daemonListen }},
"ssl": {
"enabled": {{ $node->sceheme === 'https' ? 'true' : 'false' }},
"certificate": "/etc/letsencrypt/live/{{ $node->fqdn }}/fullchain.pem",
"key": "/etc/letsencrypt/live/{{ $node->fqdn }}/privkey.pem"
}
},
"docker": {
"socket": "/var/run/docker.sock"
},
"sftp": {
"path": "{{ $node->daemonBase }}",
"port": {{ $node->daemonSFTP }},
"container": "ptdl-sftp"
},
"logger": {
"path": "logs/",
"src": false,
"level": "info",
"period": "1d",
"count": 3
},
"remote": {
"download": "{{ route('remote.download') }}",
"installed": "{{ route('remote.install') }}"
},
"uploads": {
"maximumSize": 100000000
},
"keys": [
"{{ $node->daemonSecret }}"
]
}' > config/core.json
if [ "$?" -ne "0" ]; then
$INSTALL_CMD remove $CLEANUP_PROGRAMS
cd ~ && rm -rf $INSTALL_DIR 2>&1
error_message "An error occured while attempting to save the JSON file."
fi
success_message "Congratulations, the daemon is now installed."
exit

View file

@ -1,814 +0,0 @@
{{-- Copyright (c) 2015 - 2017 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. --}}
@extends('layouts.admin')
@section('title')
Managing Node: {{ $node->name }}
@endsection
@section('scripts')
@parent
{!! Theme::js('js/vendor/socketio/socket.io.min.js') !!}
{!! Theme::js('js/bootstrap-notify.min.js') !!}
{!! Theme::js('js/vendor/chartjs/chart.min.js') !!}
{!! Theme::js('js/vendor/jquery/jquery-dateFormat.min.js') !!}
<script>
$(document).ready(function () {
$.notifyDefaults({
placement: {
from: 'bottom',
align: 'right'
},
newest_on_top: true,
delay: 2000,
animate: {
enter: 'animated fadeInUp',
exit: 'animated fadeOutDown'
}
});
});
</script>
@endsection
@section('content')
<div class="col-md-12">
<ul class="breadcrumb">
<li><a href="/admin">Admin Control</a></li>
<li><a href="/admin/nodes">Nodes</a></li>
<li class="active">{{ $node->name }}</li>
</ul>
<ul class="nav nav-tabs tabs_with_panel" id="config_tabs">
<li class="active"><a href="#tab_about" data-toggle="tab">About</a></li>
<li><a href="#tab_settings" data-toggle="tab">Settings</a></li>
<li><a href="#tab_configuration" data-toggle="tab">Configuration</a></li>
<li><a href="#tab_allocation" data-toggle="tab">Allocation</a></li>
<li><a href="#tab_servers" data-toggle="tab">Servers</a></li>
@if(count($node->servers) === 0)<li><a href="#tab_delete" data-toggle="tab">Delete</a></li>@endif
</ul>
<div class="tab-content">
<div class="tab-pane active" id="tab_about">
<div class="panel panel-default">
<div class="panel-heading"></div>
<div class="panel-body">
<table class="table table-striped" style="margin-bottom:0;">
<tbody>
<tr>
<td>Daemon Version</td>
<td><code data-attr="info-version"><i class="fa fa-refresh fa-fw fa-spin"></i></code> (Latest: <code>{{ Version::getDaemon() }}</code>)</td>
</tr>
<tr>
<td>System Information</td>
<td data-attr="info-system"><i class="fa fa-refresh fa-fw fa-spin"></i></td>
</tr>
<tr>
<td>Total CPU Cores</td>
<td data-attr="info-cpus"><i class="fa fa-refresh fa-fw fa-spin"></i></td>
</tr>
<tr>
<td>Total Servers</td>
<td>{{ count($node->servers) }}</td>
</tr>
<tr>
<td>Memory Allocated</td>
<td><strong class="{{ ($stats->memory < ($node->memory * .8)) ? 'text-success' : 'text-danger' }}">{{ is_numeric($stats->memory) ? $stats->memory : 0 }} MB</strong> of
@if(!is_null($node->memory_overallocate))
<abbr data-toggle="tooltip" data-placement="top" title="Allows up to {{ ($node->memory * (1 + ($node->memory_overallocate / 100)) - $node->memory) }} MB over">{{ $node->memory }}</abbr>
@else
{{ $node->memory }}
@endif
MB
</td>
</tr>
<tr>
<td>Disk Allocated</td>
<td><strong class="{{ ($stats->disk < ($node->disk * .8)) ? 'text-success' : 'text-danger' }}">{{ is_numeric($stats->disk) ? $stats->disk : 0 }} MB</strong> of
@if(!is_null($node->disk_overallocate))
<abbr data-toggle="tooltip" data-placement="top" title="Allows up to {{ ($node->disk * (1 + ($node->disk_overallocate / 100)) - $node->disk) }} MB over">{{ $node->disk }}</abbr>
@else
{{ $node->disk }}
@endif
MB
</td>
</tr>
</tbody>
</table>
</div>
<div class="panel-heading" style="border-top: 1px solid #ddd;"></div>
<div class="panel-body">
<div class="row">
<canvas id="chart_memory" style="max-height:300px;"></canvas>
<canvas id="chart_cpu" style="max-height:300px;"></canvas>
</div>
</div>
</div>
</div>
<div class="tab-pane" id="tab_settings">
<form method="POST" action="/admin/nodes/view/{{ $node->id }}">
<div class="panel panel-default">
<div class="panel-heading"></div>
<div class="panel-body">
<div class="alert alert-warning">
Changing some details below may require that you change the configuration file on the node as well as restart the daemon. They have been marked with <span class="label label-warning"><i class="fa fa-power-off"></i></span> below.
</div>
<div class="row">
<div class="form-group col-md-6">
<label for="name" class="control-label">Node Name</label>
<div>
<input type="text" autocomplete="off" name="name" class="form-control" value="{{ old('name', $node->name) }}" />
<p class="text-muted"><small>Character limits: <code>a-zA-Z0-9_.-</code> and <code>[Space]</code> (min 1, max 100 characters).</small></p>
</div>
</div>
<div class="form-group col-md-4">
<label for="name" class="control-label">Location</label>
<div>
<select name="location_id" class="form-control">
@foreach($locations as $location)
<option value="{{ $location->id }}" {{ (old('location_id', $node->location) === $location->id) ? 'selected' : '' }}>{{ $location->long }} ({{ $location->short }})</option>
@endforeach
</select>
</div>
</div>
<div class="form-group col-md-2">
<label for="public" class="control-label">Public <sup><a data-toggle="tooltip" data-placement="top" title="Allow automatic allocation to this Node?">?</a></sup></label>
<div>
<input type="radio" name="public" value="1" {{ (old('public', $node->public) === '1') ? 'checked' : '' }} id="public_1" checked> <label for="public_1" style="padding-left:5px;">Yes</label><br />
<input type="radio" name="public" value="0" {{ (old('public', $node->public) === '0') ? 'checked' : '' }} id="public_0"> <label for="public_0" style="padding-left:5px;">No</label>
</div>
</div>
</div>
<div class="row">
<div class="form-group col-md-6">
<label for="fqdn" class="control-label">Fully Qualified Domain Name</label>
<div>
<input type="text" autocomplete="off" name="fqdn" class="form-control" value="{{ old('fqdn', $node->fqdn) }}" />
</div>
<p class="text-muted"><small>Please enter domain name (e.g <code>node.example.com</code>) to be used for connecting to the daemon. An IP address may only be used if you are not using SSL for this node.
<a tabindex="0" data-toggle="popover" data-trigger="focus" title="Why do I need a FQDN?" data-content="In order to secure communications between your server and this node we use SSL. We cannot generate a SSL certificate for IP Addresses, and as such you will need to provide a FQDN.">Why?</a>
</small></p>
</div>
<div class="form-group col-md-6">
<label for="scheme" class="control-label"><span class="label label-warning"><i class="fa fa-power-off"></i></span> Secure Socket Layer</label>
<div class="row" style="padding: 7px 0;">
<div class="col-xs-6">
<input type="radio" name="scheme" value="https" id="scheme_ssl" {{ (old('scheme', $node->scheme) === 'https') ? 'checked' : '' }}/> <label for="scheme_ssl" style="padding-left: 5px;">Enable HTTPS/SSL</label>
</div>
<div class="col-xs-6">
<input type="radio" name="scheme" value="http" id="scheme_nossl" {{ (old('scheme', $node->scheme) === 'http') ? 'checked' : '' }}/> <label for="scheme_nossl" style="padding-left: 5px;">Disable HTTPS/SSL</label>
</div>
</div>
<p class="text-muted"><small>You should always leave SSL enabled for nodes. Disabling SSL could allow a malicious user to intercept traffic between the panel and the daemon potentially exposing sensitive information.</small></p>
</div>
</div>
</div>
<div class="panel-heading" style="border-top: 1px solid #ddd;"></div>
<div class="panel-body">
<div class="row">
<div class="form-group col-md-3 col-xs-6">
<label for="memory" class="control-label">Total Memory</label>
<div class="input-group">
<input type="text" name="memory" class="form-control" data-multiplicator="true" value="{{ old('memory', $node->memory) }}"/>
<span class="input-group-addon">MB</span>
</div>
</div>
<div class="form-group col-md-3 col-xs-6">
<label for="memory_overallocate" class="control-label">Overallocate</label>
<div class="input-group">
<input type="text" name="memory_overallocate" class="form-control" value="{{ old('memory_overallocate', $node->memory_overallocate) }}"/>
<span class="input-group-addon">%</span>
</div>
</div>
<div class="form-group col-md-3 col-xs-6">
<label for="disk" class="control-label">Disk Space</label>
<div class="input-group">
<input type="text" name="disk" class="form-control" data-multiplicator="true" value="{{ old('disk', $node->disk) }}"/>
<span class="input-group-addon">MB</span>
</div>
</div>
<div class="form-group col-md-3 col-xs-6">
<label for="disk_overallocate" class="control-label">Overallocate</label>
<div class="input-group">
<input type="text" name="disk_overallocate" class="form-control" value="{{ old('disk_overallocate', $node->disk_overallocate) }}"/>
<span class="input-group-addon">%</span>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<p class="text-muted"><small>Enter the total amount of disk space and memory avaliable for new servers. If you would like to allow overallocation of disk space or memory enter the percentage that you want to allow. To disable checking for overallocation enter <code>-1</code> into the field. Entering <code>0</code> will prevent creating new servers if it would put the node over the limit.</small></p>
</div>
</div>
</div>
<div class="panel-heading" style="border-top: 1px solid #ddd;"></div>
<div class="panel-body">
<div class="row">
<div class="form-group col-md-6">
<label for="disk_overallocate" class="control-label">Maximum Web Upload Filesize</label>
<div class="input-group">
<input type="text" name="upload_size" class="form-control" value="{{ old('upload_size', $node->upload_size) }}"/>
<span class="input-group-addon">MB</span>
</div>
<p class="text-muted"><small>Enter the maximum size of files that can be uploaded through the web-based file manager.</small></p>
</div>
</div>
</div>
<div class="panel-heading" style="border-top: 1px solid #ddd;"></div>
<div class="panel-body">
<div class="row">
<div class="col-xs-6">
<div class="row">
<div class="form-group col-md-6">
<label for="daemonListen" class="control-label"><span class="label label-warning"><i class="fa fa-power-off"></i></span> Daemon Port</label>
<div>
<input type="text" name="daemonListen" class="form-control" value="{{ old('daemonListen', $node->daemonListen) }}"/>
</div>
</div>
<div class="form-group col-md-6">
<label for="daemonSFTP" class="control-label"><span class="label label-warning"><i class="fa fa-power-off"></i></span> Daemon SFTP Port</label>
<div>
<input type="text" name="daemonSFTP" class="form-control" value="{{ old('daemonSFTP', $node->daemonSFTP) }}"/>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<p class="text-muted"><small>The daemon runs its own SFTP management container and does not use the SSHd process on the main physical server. <Strong>Do not use the same port that you have assigned for your physcial server's SSH process.</strong></small></p>
</div>
</div>
</div>
<div class="col-xs-6">
<div class="row">
<div class="form-group col-md-12">
<label for="reset_secret" class="control-label">Reset Daemon Key</label>
<div style="padding: 7px 0;">
<input type="checkbox" name="reset_secret" id="reset_secret" /> Reset Daemon Master Key
</div>
</div>
<div class="col-md-12">
<p class="text-muted"><small>Resetting the daemon master key will void any request coming from the old key. This key is used for all sensitive operations on the daemon including server creation and deletion. We suggest changing this key regularly for security.</small></p>
</div>
</div>
</div>
</div>
</div>
<div class="panel-heading" style="border-top: 1px solid #ddd;"></div>
<div class="panel-body">
<div class="row">
<div class="col-md-12">
{!! csrf_field() !!}
<input type="submit" class="btn btn-sm btn-primary" value="Update Node Information" />
</div>
</div>
</div>
</div>
</form>
</div>
<div class="tab-pane" id="tab_configuration">
<div class="panel panel-default">
<div class="panel-heading"></div>
<div class="panel-body">
<div class="col-md-8">
<p class="text-muted small">To simplify the configuration of nodes it is possible to fetch the config from the panel. A token is required for this process. The button below will generate a token and provide you with the commands necessary for automatic configuration of the node. Be aware that these tokens are only valid for 5 minutes.</p>
</div>
<div class="col-md-4 text-center">
<p><button type="button" id="configTokenBtn" class="btn btn-sm btn-primary" style="width:100%;">Generate Token</button></p>
</div>
<div class="col-md-12">
<pre><code>{{ $node->getConfigurationAsJson(true) }}</code></pre>
</div>
</div>
</div>
</div>
<div class="tab-pane" id="tab_allocation">
<div class="panel panel-default">
<div class="panel-heading"></div>
<div class="panel-body">
<h4 style="margin-top:0;">Allocate Additional Ports</h4>
<form action="{{ route('admin.nodes.post.allocations', $node->id) }}" method="POST">
<div class="row" id="duplicate">
<div class="col-md-4 fuelux">
<label for="" class="control-label">IP Address or FQDN</label>
<div class="input-group input-append dropdown combobox allocationComboBox" data-initialize="combobox">
<input type="text" name="allocate_ip[]" class="form-control pillbox_ip" style="border-right:0;">
<div class="input-group-btn">
<button type="button" class="btn btn-sm btn-primary dropdown-toggle" data-toggle="dropdown"><span class="caret"></span></button>
<ul class="dropdown-menu dropdown-menu-right">
@foreach($node->allocations->unique('ip')->values()->all() as $allocation)
<li data-action="alloc_dropdown_val" data-value="{{ $allocation->ip }}"><a href="#">{{ $allocation->ip }}</a></li>
@endforeach
</ul>
</div>
</div>
</div>
<div class="form-group col-md-7 col-xs-10 fuelux">
<label for="" class="control-label">Ports</label>
<div class="pillbox allocationPillbox" data-initialize="pillbox">
<ul class="clearfix pill-group">
<li class="pillbox-input-wrap btn-group">
<input type="text" class="form-control dropdown-toggle pillbox-add-item" placeholder="add port">
</li>
</ul>
</div>
<p class="text-muted"><small>You <strong>must</strong> enter a comma (<code>,</code>) or press the enter key after each port or range that you enter. They should appear in a blue box.</small></p>
<input name="allocate_port[]" type="hidden" class="pillboxMain"/>
</div>
<div class="form-group col-md-1 col-xs-2" style="margin-left: -10px;">
<label for="" class="control-label">&nbsp;</label>
<button class="btn btn-danger btn-allocate-delete removeClone disabled"><i class="fa fa-close"></i></button>
</div>
</div>
<div class="row">
<div class="col-md-12">
<hr />
{!! csrf_field() !!}
<input type="submit" class="btn btn-sm btn-primary" value="Add Ports" />
<button class="btn btn-success btn-sm cloneElement">Add More Rows</button>
</div>
</div>
</form>
</div>
<div class="panel-heading" style="border-top: 1px solid #ddd;"></div>
<div class="panel-body">
<div class="row">
<table class="table table-hover" style="margin-bottom:0;">
<thead style="font-weight:bold;">
<td>IP Address <i class="fa fa-fw fa-minus-square" style="font-weight:normal;color:#d9534f;cursor:pointer;" data-toggle="modal" data-target="#allocationModal"></i></td>
<td>IP Alias</td>
<td>Port</td>
<td>Assigned To</td>
<td></td>
</thead>
<tbody>
@foreach($node->allocations as $allocation)
<tr>
<td class="col-sm-3 align-middle">{{ $allocation->ip }}</td>
<td class="col-sm-3 align-middle">
<input class="form-control input-sm" type="text" value="{{ $allocation->ip_alias }}" data-action="set-alias" data-id="{{ $allocation->id }}" placeholder="none" />
<span class="input-loader"><i class="fa fa-refresh fa-spin fa-fw"></i></span>
</td>
<td class="col-sm-2 align-middle">{{ $allocation->port }}</td>
<td class="col-sm-3 align-middle">
@if(! is_null($allocation->server))
<a href="{{ route('admin.servers.view', $allocation->server_id) }}">{{ $allocation->server->name }}</a>
@endif
</td>
<td class="col-sm-1 align-middle">
@if(is_null($allocation->server_id))
<a href="#" data-action="deallocate" data-id="{{ $allocation->id }}"><span class="badge label-danger"><i class="fa fa-trash-o"></i></span></a>
@else
<span class="badge label-default"><i class="fa fa-trash-o"></i></span>
@endif
</td>
</tr>
@endforeach
</tbody>
</table>
<div class="col-md-12 text-center">
{{ $node->allocations->appends(['tab' => 'tab_allocation'])->render() }}
</div>
</div>
</div>
</div>
</div>
<div class="tab-pane" id="tab_servers">
<div class="panel panel-default">
<div class="panel-heading"></div>
<div class="panel-body">
<div class="alert alert-info">
The data below is live output from the daemon. CPU usage is displayed relative to the assigned CPU allocation. For example, if a server is assigned <code>10%</code> and the CPU usage below displays <code>90%</code> that means the server is using <code>9%</code> of the total system CPU.
</div>
<table class="table table-striped" style="margin-bottom: 0;">
<thead>
<tr>
<th>Name</th>
<th>Owner</th>
<th>Service</th>
<th class="text-center">Memory</th>
<th class="text-center">Disk</th>
<th class="text-center">CPU</th>
<th class="text-center">Status</th>
</tr>
</thead>
<tbody>
@foreach($node->servers as $server)
<tr data-server="{{ $server->uuid }}">
<td><a href="/admin/servers/view/{{ $server->id }}">{{ $server->name }}</a></td>
<td><a href="/admin/users/view/{{ $server->owner_id }}"><code>{{ $server->user->email }}</a></a></td>
<td>{{ $server->service->name }}</td>
<td class="text-center"><span data-action="memory">--</span> / {{ $server->memory === 0 ? '&infin;' : $server->memory }} MB</td>
<td class="text-center">{{ $server->disk }} MB</td>
<td class="text-center"><span data-action="cpu" data-cpumax="{{ $server->cpu }}">--</span> %</td>
<td class="text-center" data-action="status">--</td>
</tr>
@endforeach
</tbody>
</table>
</div>
</div>
</div>
@if(count($node->servers) === 0)
<div class="tab-pane" id="tab_delete">
<div class="panel panel-default">
<div class="panel-heading"></div>
<div class="panel-body">
<div class="row">
<div class="col-xs-4 text-center">
<form action="{{ route('admin.nodes.delete', $node->id) }}" method="POST" id="deleteNodeForm">
{!! method_field('DELETE') !!}
{!! csrf_field() !!}
<input type="submit" value="Delete Node" class="btn btn-sm btn-danger" />
</form>
</div>
<div class="col-xs-8">
<div class="alert alert-danger" style="margin-bottom:0;">Deleting this node is a permanent action, it cannot be undone.</div>
</div>
</div>
</div>
</div>
</div>
@endif
</div>
<div class="row">
<div class="col-xs-11" id="col11_setter"></div>
</div>
</div>
<div class="modal fade" id="allocationModal" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title">Delete Allocations for IP Block</h4>
</div>
<form action="{{ route('admin.nodes.view', $node->id) }}/deallocate/block" method="POST">
<div class="modal-body">
<div class="row">
<div class="col-md-12">
<select class="form-control" name="ip">
@foreach($node->allocations->unique('ip')->values()->all() as $allocation)
<option value="{{ $allocation->ip }}">{{ $allocation->ip }}</option>
@endforeach
</select>
</div>
</div>
</div>
<div class="modal-footer">
{{{ csrf_field() }}}
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<button type="submit" class="btn btn-danger">Delete Allocations</button>
</div>
</form>
</div>
</div>
</div>
<script>
$(document).ready(function () {
$('#sidebar_links').find("a[href='/admin/nodes']").addClass('active');
$('[data-toggle="tooltip"]').tooltip();
$('[data-toggle="popover"]').popover({
placement: 'auto'
});
$('#deleteNodeForm').submit(function (event) {
event.preventDefault();
swal({
type: 'warning',
title: 'Are You Sure?',
text: 'This will immediately delete this node, there is no undo.',
showCancelButton: true,
allowOutsideClick: true,
confirmButtonText: 'Delete',
confirmButtonColor: '#d9534f',
}, function () {
event.target.submit();
});
});
$('#configTokenBtn').on('click', function (event) {
$.getJSON('{{ route('admin.nodes.configuration-token', $node->id) }}')
.done(function (data) {
swal({
type: 'success',
title: 'Token created.',
text: 'Your token will expire at ' + data.expires_at + '<br /><br />' +
'<p>To auto-configure your node run<br /><small><pre>npm run configure -- --panel-url {{ config('app.url') }} --token '+data.token+'</pre></small></p>',
html: true
})
})
.fail(function () {
swal({
title: 'Error',
text: 'Something went wrong creating your token.',
type: 'error'
});
})
})
$('.cloneElement').on('click', function (event) {
event.preventDefault();
var rnd = randomKey(10);
var cloned = $('#duplicate').clone().attr('id', rnd);
cloned.find('.allocationPillbox').removeClass('allocationPillbox').addClass('allocationPillbox_' + rnd);
cloned.find('.pillboxMain').removeClass('pillboxMain').addClass('pillbox_' + rnd);
cloned.find('.removeClone').removeClass('disabled').attr('data-parent', rnd);
cloned.find('.pillbox_ip').removeClass('pillbox_ip').addClass('pillbox_ip_' + rnd);
cloned.insertAfter('#duplicate');
$('.allocationPillbox_' + rnd).pillbox();
$('.allocationPillbox_' + rnd).on('added.fu.pillbox edited.fu.pillbox removed.fu.pillbox', function pillboxChanged() {
$('.pillbox_' + rnd).val(JSON.stringify($('.allocationPillbox_' + rnd).pillbox('items')));
});
$('.removeClone').unbind().on('click', function (event) {
event.preventDefault();
var element = $(this);
$('#' + element.attr('data-parent')).slideUp(function () {
element.remove();
$('.pillbox_' + element.attr('data-parent')).remove();
$('.pillbox_ip_' + element.attr('data-parent')).remove();
});
});
});
$('.allocationPillbox').pillbox();
$('.allocationComboBox').combobox();
$('.allocationPillbox').on('added.fu.pillbox edited.fu.pillbox removed.fu.pillbox', function pillboxChanged() {
$('.pillboxMain').val(JSON.stringify($('.allocationPillbox').pillbox('items')));
});
var notifySocketError = false;
var Status = {
0: 'Off',
1: 'On',
2: 'Starting',
3: 'Stopping'
};
// Main Socket Object
var socket = io('{{ $node->scheme }}://{{ $node->fqdn }}:{{ $node->daemonListen }}/stats/', {
'query': 'token={{ $node->daemonSecret }}'
});
// Socket Failed to Connect
socket.io.on('connect_error', function (err) {
if(typeof notifySocketError !== 'object') {
notifySocketError = $.notify({
message: '{!! trans('server.ajax.socket_error') !!}'
}, {
type: 'danger',
delay: 0
});
}
});
// Connected to Socket Successfully
socket.on('connect', function () {
if (notifySocketError !== false) {
notifySocketError.close();
notifySocketError = false;
}
});
socket.on('error', function (err) {
console.error('There was an error while attemping to connect to the websocket: ' + err + '\n\nPlease try loading this page again.');
});
var ctc = $('#chart_cpu');
var timeLabels = [];
var cpuData = [];
var CPUChart = new Chart(ctc, {
type: 'line',
data: {
labels: timeLabels,
datasets: [
{
label: "Percent Use",
fill: false,
lineTension: 0.03,
backgroundColor: "#00A1CB",
borderColor: "#00A1CB",
borderCapStyle: 'butt',
borderDash: [],
borderDashOffset: 0.0,
borderJoinStyle: 'miter',
pointBorderColor: "rgba(75,192,192,1)",
pointBackgroundColor: "#fff",
pointBorderWidth: 1,
pointHoverRadius: 5,
pointHoverBackgroundColor: "rgba(75,192,192,1)",
pointHoverBorderColor: "rgba(220,220,220,1)",
pointHoverBorderWidth: 2,
pointRadius: 1,
pointHitRadius: 10,
data: cpuData,
spanGaps: false,
}
]
},
options: {
title: {
display: true,
text: 'CPU Usage (as Percent Total)'
},
legend: {
display: false,
},
animation: {
duration: 1,
}
}
});
var ctm = $('#chart_memory');
var memoryData = [];
var MemoryChart = new Chart(ctm, {
type: 'line',
data: {
labels: timeLabels,
datasets: [
{
label: "Memory Use",
fill: false,
lineTension: 0.03,
backgroundColor: "#01A4A4",
borderColor: "#01A4A4",
borderCapStyle: 'butt',
borderDash: [],
borderDashOffset: 0.0,
borderJoinStyle: 'miter',
pointBorderColor: "rgba(75,192,192,1)",
pointBackgroundColor: "#fff",
pointBorderWidth: 1,
pointHoverRadius: 5,
pointHoverBackgroundColor: "rgba(75,192,192,1)",
pointHoverBorderColor: "rgba(220,220,220,1)",
pointHoverBorderWidth: 2,
pointRadius: 1,
pointHitRadius: 10,
data: memoryData,
spanGaps: false,
}
]
},
options: {
title: {
display: true,
text: 'Memory Usage (in Megabytes)'
},
legend: {
display: false,
},
animation: {
duration: 1,
}
}
});
socket.on('live-stats', function (data) {
if (cpuData.length > 10) {
cpuData.shift();
memoryData.shift();
timeLabels.shift();
}
cpuData.push(data.stats.cpu);
memoryData.push(parseInt(data.stats.memory / (1024 * 1024)));
var m = new Date();
timeLabels.push($.format.date(new Date(), 'HH:mm:ss'));
CPUChart.update();
MemoryChart.update();
$.each(data.servers, function (uuid, info) {
var element = $('tr[data-server="' + uuid + '"]');
element.find('[data-action="status"]').html(Status[info.status]);
if (info.status !== 0) {
var cpuMax = element.find('[data-action="cpu"]').data('cpumax');
var currentCpu = info.proc.cpu.total;
if (cpuMax !== 0) {
currentCpu = parseFloat(((info.proc.cpu.total / cpuMax) * 100).toFixed(2).toString());
}
element.find('[data-action="memory"]').html(parseInt(info.proc.memory.total / (1024 * 1024)));
element.find('[data-action="cpu"]').html(currentCpu);
} else {
element.find('[data-action="memory"]').html('--');
element.find('[data-action="cpu"]').html('--');
}
});
});
$('span[data-action="delete"]').hover(function() {
$(this).find('i').css('color', '#d9534f').removeClass('fa-square-o').addClass('fa-minus-square');
}, function () {
$(this).find('i').css('color', 'inherit').addClass('fa-square-o').removeClass('fa-minus-square');
});
$('a[data-action="deallocate"]').click(function (event) {
event.preventDefault();
var element = $(this);
var allocation = $(this).data('id');
swal({
title: '',
text: 'Are you sure you want to delete this allocation?',
type: 'warning',
showCancelButton: true,
allowOutsideClick: true,
closeOnConfirm: false,
confirmButtonText: 'Delete',
confirmButtonColor: '#d9534f',
showLoaderOnConfirm: true
}, function () {
$.ajax({
method: 'DELETE',
url: '{{ route('admin.nodes.view', $node->id) }}/deallocate/single/' + allocation,
headers: {
'X-CSRF-TOKEN': '{{ csrf_token() }}'
}
}).done(function (data) {
element.parent().parent().addClass('warning').delay(100).fadeOut();
swal({
type: 'success',
title: 'Port Deleted!',
});
}).fail(function (jqXHR) {
console.error(jqXHR);
swal({
title: 'Whoops!',
text: jqXHR.responseJSON.error,
type: 'error'
});
});
});
});
var typingTimer;
$('input[data-action="set-alias"]').keyup(function () {
clearTimeout(typingTimer);
$(this).parent().removeClass('has-error has-success');
typingTimer = setTimeout(sendAlias, 700, $(this));
});
var fadeTimers = [];
function sendAlias(element) {
element.parent().find('.input-loader').show();
clearTimeout(fadeTimers[element.data('id')]);
$.ajax({
method: 'POST',
url: '{{ route('admin.nodes.alias', $node->id) }}',
headers: {
'X-CSRF-TOKEN': '{{ csrf_token() }}'
},
data: {
alias: element.val(),
allocation: element.data('id')
}
}).done(function (data) {
element.parent().addClass('has-success');
}).fail(function (jqXHR) {
console.error(jqXHR);
element.parent().addClass('has-error');
}).always(function () {
element.parent().find('.input-loader').hide();
fadeTimers[element.data('id')] = setTimeout(clearHighlight, 2500, element);
});
}
function clearHighlight(element) {
element.parent().removeClass('has-error has-success');
}
(function getInformation() {
$.ajax({
method: 'GET',
url: '{{ $node->scheme }}://{{ $node->fqdn }}:{{ $node->daemonListen }}',
timeout: 5000,
headers: {
'X-Access-Token': '{{ $node->daemonSecret }}'
},
}).done(function (data) {
$('[data-attr="info-version"]').html(data.version);
$('[data-attr="info-system"]').html(data.system.type + '(' + data.system.arch + ') <code>' + data.system.release + '</code>');
$('[data-attr="info-cpus"]').html(data.system.cpus);
}).fail(function (jqXHR) {
}).always(function() {
setTimeout(getInformation, 10000);
});
})();
});
</script>
@endsection

View file

@ -1,83 +0,0 @@
{{-- Copyright (c) 2015 - 2017 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. --}}
@extends('layouts.admin')
@section('title')
Server List
@endsection
@section('content')
<div class="col-md-12">
<ul class="breadcrumb">
<li><a href="/admin">Admin Control</a></li>
<li class="active">Servers</li>
</ul>
<h3>All Servers</h3><hr />
<form method="GET" style="margin-bottom:20px;">
<div class="input-group">
<input type="text" name="filter" class="form-control" value="{{ urldecode(request()->filter) }}" placeholder="search term" />
<div class="input-group-btn">
<button type="submit" class="btn btn-sm btn-primary">Filter Servers</button>
</div>
</div>
</form>
<table class="table table-bordered table-hover">
<thead>
<tr>
<th>Server Name</th>
<th>Owner</th>
<th>Node</th>
<th class="hidden-xs">SFTP Username</th>
</tr>
</thead>
<tbody>
@foreach ($servers as $server)
<tr
@if($server->suspended === 1 && !$server->trashed())
class="warning"
@elseif($server->trashed())
class="danger"
@endif
data-server="{{ $server->uuidShort }}">
<td>
<a href="/admin/servers/view/{{ $server->id }}">{{ $server->name }}</a>
@if($server->suspended === 1 && !$server->trashed())
<span class="label label-warning">Suspended</span>
@elseif($server->trashed())
<span class="label label-danger">Pending Deletion</span>
@endif
</td>
<td><a href="/admin/users/view/{{ $server->user->id }}">{{ $server->user->email }}</a></td>
<td><a href="/admin/nodes/view/{{ $server->node->id }}">{{ $server->node->name }}</a></td>
<td class="hidden-xs"><code>{{ $server->username }}</code></td>
</tr>
@endforeach
</tbody>
</table>
<div class="row">
<div class="col-md-12 text-center">{!! $servers->render() !!}</div>
</div>
</div>
<script>
$(document).ready(function () {
$('#sidebar_links').find("a[href='/admin/servers']").addClass('active');
});
</script>
@endsection

View file

@ -1,511 +0,0 @@
{{-- Copyright (c) 2015 - 2017 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. --}}
@extends('layouts.admin')
@section('title')
Create New Server
@endsection
@section('scripts')
@parent
{!! Theme::js('js/vendor/typeahead/typeahead.min.js') !!}
@endsection
@section('content')
<div class="col-md-12">
<ul class="breadcrumb">
<li><a href="/admin">Admin Control</a></li>
<li><a href="/admin/servers">Servers</a></li>
<li class="active">Create New Server</li>
</ul>
<h3>Create New Server</h3><hr />
<form action="/admin/servers/new" method="POST">
<div class="well">
<div class="row">
<div class="form-group col-md-6">
<label for="name" class="control-label">Server Name</label>
<div>
<input type="text" autocomplete="off" name="name" class="form-control" value="{{ old('name') }}" />
<p class="text-muted"><small><em>Character limits: <code>a-z A-Z 0-9 _ - .</code> and <code>[Space]</code> (max 200 characters).</em></small></p>
</div>
</div>
<div class="form-group col-md-6">
<label for="owner" class="control-label">Owner Email</label>
<div>
{{-- Hacky workaround to prevent Safari and Chrome from trying to suggest emails here --}}
<input id="fake_user_name" name="fake_user[name]" style="position:absolute; top:-10000px;" tabindex="5" type="text" value="Autofill Me">
<input type="text" autocomplete="off" name="owner" class="form-control" value="{{ old('owner', Input::get('email')) }}" />
</div>
</div>
</div>
</div>
<div id="load_settings">
<div class="well">
<div class="row">
<div class="ajax_loading_box" style="display:none;"><i class="fa fa-refresh fa-spin ajax_loading_position"></i></div>
<div class="form-group col-md-6">
<label for="location" class="control-label">Server Location</label>
<div>
<select name="location_id" id="getLocation" class="form-control">
<option disabled selected> -- Select a Location</option>
@foreach($locations as $location)
<option value="{{ $location->id }}">{{ $location->long }} ({{ $location->short }})</option>
@endforeach
</select>
<p class="text-muted"><small>The location in which this server will be deployed.</small></p>
</div>
</div>
<div class="form-group col-md-6 hidden" id="allocationNode">
<label for="node" class="control-label">Server Node</label>
<div>
<select name="node_id" id="getNode" class="form-control">
<option disabled selected> -- Select a Node</option>
</select>
<p class="text-muted"><small>The node which this server will be deployed to.</small></p>
</div>
</div>
</div>
<div class="row">
<div class="form-group col-md-6 hidden" id="allocationIP">
<label for="ip" class="control-label">Server IP</label>
<div>
<select name="ip" id="getIP" class="form-control">
<option disabled selected> -- Select an IP</option>
</select>
<p class="text-muted"><small>Select the main IP that this server will be listening on. You can assign additional open IPs and ports below.</small></p>
</div>
</div>
<div class="form-group col-md-6 hidden" id="allocationPort">
<label for="port" class="control-label">Server Port</label>
<div>
<select name="port" id="getPort" class="form-control"></select>
<p class="text-muted"><small>Select the main port that this server will be listening on.</small></p>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12 fuelux">
<hr style="margin-top: 10px;"/>
<div class="checkbox highlight" style="margin: 0;">
<label class="checkbox-custom highlight" data-initialize="checkbox">
<input class="sr-only" name="auto_deploy" type="checkbox" @if(isset($oldInput['auto_deploy']))checked="checked"@endif value="1"> <strong>Enable Automatic Deployment</strong>
<p class="text-muted"><small>Check this box if you want the panel to automatically select a node and allocation for this server in the given location.</small><p>
</label>
</div>
</div>
</div>
</div>
</div>
<div class="well">
<div class="row">
<div class="form-group col-md-4 col-xs-4">
<label for="memory" class="control-label">Memory</label>
<div class="input-group">
<input type="text" name="memory" data-multiplicator="true" class="form-control" value="{{ old('memory') }}"/>
<span class="input-group-addon">MB</span>
</div>
</div>
<div class="form-group col-md-4 col-xs-4">
<label for="memory" class="control-label">Swap</label>
<div class="input-group">
<input type="text" name="swap" data-multiplicator="true" class="form-control" value="{{ old('swap', 0) }}"/>
<span class="input-group-addon">MB</span>
</div>
</div>
<div class="form-group col-md-4 col-xs-4">
<label for="memory" class="control-label">OOM Killer</label>
<div>
<span class="input-group-addon" style="height:36px;">
<input type="checkbox" name="oom_disabled"/>
</span>
<span class="input-group-addon" style="height:36px;">
Disable OOM Killer
</span>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<p class="text-muted"><small>If you do not want to assign swap space to a server simply put <code>0</code> for the value, or <code>-1</code> to allow unlimited swap space. If you want to disable memory limiting on a server simply enter <code>0</code> into the memory field. We suggest leaving OOM Killer enabled unless you know what you are doing, disabling it could cause your server to hang unexpectedly.</small><p>
</div>
</div>
<div class="row">
<div class="form-group col-md-4 col-xs-4">
<label for="disk" class="control-label">Disk Space</label>
<div class="input-group">
<input type="text" name="disk" data-multiplicator="true" class="form-control" value="{{ old('disk') }}"/>
<span class="input-group-addon">MB</span>
</div>
</div>
<div class="form-group col-md-4 col-xs-4">
<label for="cpu" class="control-label">CPU Limit</label>
<div class="input-group">
<input type="text" name="cpu" class="form-control" value="{{ old('cpu', 0) }}"/>
<span class="input-group-addon">%</span>
</div>
</div>
<div class="form-group col-md-4 col-xs-4">
<label for="io" class="control-label">Block I/O</label>
<div class="input-group">
<input type="text" name="io" class="form-control" value="{{ old('io', 500) }}"/>
<span class="input-group-addon">I/O</span>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<p class="text-muted"><small>If you do not want to limit CPU usage set the value to <code>0</code>. To determine a value, take the number <em>physical</em> cores and multiply it by 100. For example, on a quad core system <code>(4 * 100 = 400)</code> there is <code>400%</code> available. To limit a server to using half of a single core, you would set the value to <code>50</code>. To allow a server to use up to two physical cores, set the value to <code>200</code>. BlockIO should be a value between <code>10</code> and <code>1000</code>. Please see <a href="https://docs.docker.com/engine/reference/run/#/block-io-bandwidth-blkio-constraint" target="_blank">this documentation</a> for more information about it.</small><p>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6" id="load_services">
<div class="well">
<div class="row">
<div class="ajax_loading_box" style="display:none;"><i class="fa fa-refresh fa-spin ajax_loading_position"></i></div>
<div class="form-group col-md-12">
<label for="service_id" class="control-label">Service Type</label>
<div>
<select name="service_id" id="getService" class="form-control">
<option disabled selected> -- Select a Service</option>
@foreach($services as $service)
<option value="{{ $service->id }}">{{ $service->name }}</option>
@endforeach
</select>
<p class="text-muted"><small>Select the type of service that this server will be running.</small></p>
</div>
</div>
<div class="form-group col-md-12 hidden">
<label for="option_id" class="control-label">Service Option</label>
<div>
<select name="option_id" id="getOption" class="form-control">
<option disabled selected> -- Select a Service Option</option>
</select>
<p class="text-muted"><small>Select the type of service that this server will be running.</small></p>
</div>
</div>
<div class="form-group col-md-12 hidden">
<label for="pack_id" class="control-label">Service Pack</label>
<div>
<select name="pack_id" id="getPack" class="form-control">
<option disabled selected> -- Select a Service Pack</option>
</select>
<p class="text-muted"><small>Select the service pack that should be used for this server. This option can be changed later.</small></p>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-6">
<div class="well">
<div class="row">
<div class="form-group col-md-12">
<label for="use_custom_image" class="control-label">Use Custom Docker Image</label>
<div class="input-group">
<span class="input-group-addon">
<input @if(old('use_custom_image') === 'use_custom_image')checked="checked"@endif type="checkbox" name="use_custom_image"/>
</span>
<input type="text" class="form-control" name="custom_image_name" value="{{ old('custom_image_name') }}" disabled />
</div>
<p class="text-muted"><small>If you would like to use a custom docker image for this server please enter it here. Most users can ignore this option.</small></p>
</div>
</div>
</div>
</div>
</div>
<div class="well" id="ServiceOption" style="display:none;">
<div class="row">
<div class="form-group col-md-12">
<h3 class="nopad">Service Setup &amp; Options</h3>
<hr />
<label for="startup" class="control-label">Startup Command</label>
<div class="input-group">
<span class="input-group-addon" id="startupExec"></span>
<input type="text" class="form-control" name="startup" value="{{ old('startup') }}" />
</div>
<p class="text-muted"><small>The following data replacers are avaliable for the startup command: <code>@{{SERVER_MEMORY}}</code>, <code>@{{SERVER_IP}}</code>, and <code>@{{SERVER_PORT}}</code>. They will be replaced with the allocated memory, server ip, and server port respectively.</small></p>
</div>
</div>
<div class="row">
<div class="col-md-12">
<div class="alert alert-info">Some service options have additional environment variables that you can define for a given instance. They will show up below when you select a service option. If none show up, chances are that none were defined, and there is nothing to worry about.</div>
</div>
</div>
<div class="row" id="ServerVariable"></div>
</div>
<div class="well">
<div class="row">
<div class="col-md-12 text-center">
{!! csrf_field() !!}
<input type="submit" class="btn btn-primary btn-sm" value="Create New Server" />
</div>
</div>
</div>
</form>
</div>
<script>
$(document).ready(function () {
$('#sidebar_links').find("a[href='/admin/servers/new']").addClass('active');
$('input[name="use_custom_image"]').change(function () {
$('input[name="custom_image_name"]').val('').prop('disabled', !($(this).is(':checked')));
});
// Typeahead
$.ajax({
type: 'GET',
url: '{{ route('admin.users.json') }}',
}).done(function (data) {
$('input[name="owner"]').typeahead({ fitToElement: true, source: data });
}).fail(function (jqXHR) {
alert('Could not initialize user email typeahead.')
console.log(jqXHR);
});
var nodeData = null;
var currentLocation = null;
var currentNode = null;
var currentService = null;
$('#getLocation').on('change', function (event) {
if ($('#getLocation').val() === '' || $('#getLocation').val() === currentLocation) {
return;
}
currentLocation = $('#getLocation').val();
currentNode = null;
// Hide Existing, and Reset contents
$('#getNode').html('<option disabled selected> -- Select a Node</option>').parent().parent().addClass('hidden');
$('#getIP').html('<option disabled selected> -- Select an IP</option>').parent().parent().addClass('hidden');
$('#getPort').html('').parent().parent().addClass('hidden');
handleLoader('#load_settings', true);
$.ajax({
method: 'POST',
url: '/admin/servers/new/get-nodes',
headers: {
'X-CSRF-TOKEN': '{{ csrf_token() }}'
},
data: {
location: $('#getLocation').val()
}
}).done(function (data) {
//var data = $.parseJSON(data);
$.each(data, function (i, item) {
var isPublic = (item.public !== 1) ? '(Private Node)' : '';
$('#getNode').append('<option value="' + item.id + '">' + item.name + ' ' + isPublic + '</option>');
});
$('#getNode').parent().parent().removeClass('hidden')
}).fail(function (jqXHR) {
alert('An error occured while attempting to load a list of nodes in this location.');
currentLocation = null;
console.error(jqXHR);
}).always(function () {
handleLoader('#load_settings');
})
});
$('#getNode').on('change', function (event) {
if ($('#getNode').val() === '' || $('#getNode').val() === currentNode) {
return;
}
currentNode = $('#getNode').val();
// Hide Existing, and Reset contents
$('#getIP').html('<option disabled selected> -- Select an IP</option>').parent().parent().addClass('hidden');
$('#getPort').html('').parent().parent().addClass('hidden');
handleLoader('#load_settings', true);
$.ajax({
method: 'POST',
url: '/admin/servers/new/get-ips',
headers: {
'X-CSRF-TOKEN': '{{ csrf_token() }}'
},
data: {
node: $('#getNode').val()
}
}).done(function (data) {
nodeData = data;
$.each(data, function (ip, ports) {
$('#getIP').append('<option value="' + ip + '">' + ip + '</option>');
});
$('#getIP').parent().parent().removeClass('hidden');
}).fail(function (jqXHR) {
alert('An error occured while attempting to get IPs and Ports avaliable on this node.');
currentNode = null;
console.error(jqXHR);
}).always(function () {
handleLoader('#load_settings');
});
});
$('#getIP').on('change', function (event) {
if ($('#getIP').val() === '') {
return;
}
$('#getPort').html('');
$.each(nodeData[$('#getIP').val()], function (i, port) {
$('#getPort').append('<option value="' + port +'">' + port + '</option>');
});
$('#getPort').parent().parent().removeClass('hidden');
});
$('input[name="auto_deploy"]').change(function () {
if ($(this).is(':checked')) {
$('#allocationPort, #allocationIP, #allocationNode').hide();
} else {
currentLocation = null;
$('#allocationPort, #allocationIP, #allocationNode').show().addClass('hidden');
$('#getLocation').trigger('change', function (e) {
alert('triggered');
});
}
});
$('#getService').on('change', function (event) {
if ($('#getService').val() === '' || $('#getService').val() === currentService) {
return;
}
currentService = $('#getService').val();
handleLoader('#load_services', true);
$('#ServiceOption').slideUp();
$('#getOption').html('<option disabled selected> -- Select a Service Option</option>');
$('#getPack').html('<option disabled selected> -- Select a Service Pack</option>');
$.ajax({
method: 'POST',
url: '/admin/servers/new/service-options',
headers: {
'X-CSRF-TOKEN': '{{ csrf_token() }}'
},
data: {
service: $('#getService').val()
}
}).done(function (data) {
$.each(data, function (i, option) {
$('#getOption').append('<option value="' + option.id + '" data-image="' + option.docker_image + '">' + option.name + '</option>');
});
$('#getOption').parent().parent().removeClass('hidden');
}).fail(function (jqXHR) {
alert('An error occured while attempting to list options for this service.');
currentService = null;
console.error(jqXHR);
}).always(function () {
handleLoader('#load_services');
});
});
$('#getOption').on('change', function (event) {
handleLoader('#load_services', true);
handleLoader('#ServiceOption', true);
$('#ServerVariable').html('');
$('input[name="custom_image_name"]').val($(this).find(':selected').data('image'));
$('#getPack').html('<option disabled selected> -- Select a Service Pack</option>');
$.ajax({
method: 'POST',
url: '/admin/servers/new/option-details',
headers: {
'X-CSRF-TOKEN': '{{ csrf_token() }}'
},
data: {
option: $('#getOption').val()
}
}).done(function (data) {
$('#startupExec').html(data.exec);
$('input[name="startup"]').val(data.startup);
$.each(data.packs, function (i, item) {
$('#getPack').append('<option value="' + item.id + '">' + item.name + ' (' + item.version + ')</option>');
});
$('#getPack').append('<option value="0">No Service Pack</option>').parent().parent().removeClass('hidden');
$.each(data.variables, function (i, item) {
var isRequired = (item.required === 1) ? '<span class="label label-primary">Required</span> ' : '';
var dataAppend = ' \
<div class="form-group col-md-12">\
<label for="var_ref_' + item.id + '" class="control-label">' + isRequired + item.name + '</label> \
<div>\
<input type="text" autocomplete="off" name="env_' + item.env_variable + '" class="form-control" value="' + item.default_value + '" />\
<p class="text-muted"><small>' + item.description + '</small></p>\
<p class="text-muted"><small>Regex Requirements for Input: <code>' + item.regex + '</code></small></p>\
<p class="text-muted"><small>Access in Startup: <code>@{{' + item.env_variable + '}}</code></small></p>\
</div>\
</div>\
';
$('#ServerVariable').append(dataAppend);
});
$('#ServiceOption').slideDown();
}).fail(function (jqXHR) {
console.error(jqXHR);
}).always(function () {
handleLoader('#load_services');
handleLoader('#ServiceOption');
});
});
// Show Loading Animation
function handleLoader (element, show) {
var spinner = $(element).find('.ajax_loading_position');
var popover = $(element).find('.ajax_loading_box');
// Show Animation
if (typeof show !== 'undefined') {
var height = $(element).height();
var width = $(element).width();
var center_height = (height / 2) - 16;
var center_width = (width / 2) - 16;
spinner.css({
'top': center_height,
'left': center_width,
'font-size': '32px'
});
popover.css({
'height': height,
'margin': '-20px 0 0 -5px',
'width': width
}).fadeIn();
} else {
popover.hide();
}
}
});
</script>
@endsection

View file

@ -1,97 +0,0 @@
{{-- Copyright (c) 2015 - 2017 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. --}}
@extends('layouts.admin')
@section('title')
Administration
@endsection
@section('content')
<div class="col-md-12">
<ul class="breadcrumb">
<li><a href="/admin">Admin Control</a></li>
<li class="active">Settings</li>
</ul>
<h3 class="nopad">Panel Settings</h3><hr />
<form action="{{ route('admin.settings') }}" method="POST">
<div class="row">
<div class="form-group col-md-6">
<label class="control-label">Company Name:</label>
<div>
<input type="text" class="form-control" name="company" value="{{ old('company', Settings::get('company')) }}" />
<p class="text-muted"><small>This is the name that is used throughout the panel and in emails sent to clients.</small></p>
</div>
</div>
<div class="form-group col-md-6">
<label class="control-label">Default Language:</label>
<div>
<select name="default_language" class="form-control">
<option value="de" @if(Settings::get('default_language') === 'de')selected @endif>Deutsch</option>
<option value="en" @if(Settings::get('default_language', 'en') === 'en')selected @endif>English</option>
<option value="es" @if(Settings::get('default_language') === 'es')selected @endif>Espa&ntilde;ol</option>
<option value="fr" @if(Settings::get('default_language') === 'fr')selected @endif>Fran&ccedil;ais</option>
<option value="it" @if(Settings::get('default_language') === 'it')selected @endif>Italiano</option>
<option value="pl" @if(Settings::get('default_language') === 'pl')selected @endif>Polski</option>
<option value="pt" @if(Settings::get('default_language') === 'pt')selected @endif>Portugu&ecirc;s</option>
<option value="ru" @if(Settings::get('default_language') === 'ru')selected @endif>&#1088;&#1091;&#1089;&#1089;&#1082;&#1080;&#1081;</option>
<option value="se" @if(Settings::get('default_language') === 'se')selected @endif>Svenska</option>
<option value="zh" @if(Settings::get('default_language') === 'zh')selected @endif>&#20013;&#22269;&#30340;的</option>
</select>
<p class="text-muted"><small>This is the default language that all clients will use unless they manually change it.</small></p>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<div class="alert alert-info">In order to modify your SMTP settings for sending mail you will need to edit the <code>.env</code> file in this project's root folder.</div>
</div>
</div>
<div class="row">
<div class="form-group col-md-6">
<label class="control-label">Send Emails From:</label>
<div>
<input type="text" class="form-control" name="email_from" value="{{ old('email_from', Settings::get('email_from', env('MAIL_FROM', 'you@example.com'))) }}" />
<p class="text-muted"><small>The email address that panel emails will be sent from. Note that some SMTP services require this to match for a given API key.</small></p>
</div>
</div>
<div class="form-group col-md-6">
<label class="control-label">Email Sender Name:</label>
<div>
<input type="text" class="form-control" name="email_sender_name" value="{{ old('email_sender_name', Settings::get('email_sender_name', env('MAIL_FROM_NAME', 'Pterodactyl Panel'))) }}" />
<p class="text-muted"><small>The name that emails will appear to come from.</small></p>
</div>
</div>
</div>
<div class="well well-sm">
<div class="row">
<div class="col-md-12">
{!! csrf_field() !!}
<input type="submit" class="btn btn-sm btn-primary" value="Modify Settings">
</div>
</div>
</div>
</form>
</div>
<script>
$(document).ready(function () {
$('#sidebar_links').find("a[href='/admin/settings']").addClass('active');
});
</script>
@endsection

View file

@ -1,73 +0,0 @@
{{-- Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com> --}}
{{-- Some Modifications (c) 2015 Dylan Seidt <dylan.seidt@gmail.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. --}}
@extends('layouts.admin')
@section('title')
Account List
@endsection
@section('content')
<div class="col-md-12">
<ul class="breadcrumb">
<li><a href="/admin">Admin Control</a></li>
<li class="active">Accounts</li>
</ul>
<h3>All Registered Users</h3><hr />
<form method="GET" style="margin-bottom:20px;">
<div class="input-group">
<input type="text" name="filter" class="form-control" value="{{ urldecode(Input::get('filter')) }}" placeholder="search term" />
<div class="input-group-btn">
<button type="submit" class="btn btn-sm btn-primary">Filter Users</button>
</div>
</div>
</form>
<table class="table table-striped table-bordered table-hover">
<thead>
<tr>
<th>ID</td>
<th>Email</td>
<th>Client Name</th>
<th>Username</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach ($users as $user)
<tr class="align-middle">
<td><code>#{{ $user->id }}</code></td>
<td><a href="{{ route('admin.users.view', $user->id) }}">{{ $user->email }}</a></td>
<td>{{ $user->name_last }}, {{ $user->name_first }}</td>
<td><code>{{ $user->username }}</code></td>
<td class="text-center"><img src="https://www.gravatar.com/avatar/{{ md5(strtolower($user->email)) }}?s=20" class="img-circle" /></td>
</tr>
@endforeach
</tbody>
</table>
<div class="row">
<div class="col-md-12 text-center">{!! $users->render() !!}</div>
</div>
</div>
<script>
$(document).ready(function () {
$('#sidebar_links').find("a[href='/admin/users']").addClass('active');
});
</script>
@endsection

View file

@ -1,132 +0,0 @@
{{-- Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com> --}}
{{-- Some Modifications (c) 2015 Dylan Seidt <dylan.seidt@gmail.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. --}}
@extends('layouts.admin')
@section('title')
New Account
@endsection
@section('content')
<div class="col-md-12">
<ul class="breadcrumb">
<li><a href="/admin">Admin Controls</a></li>
<li><a href="/admin/users">Accounts</a></li>
<li class="active">Add New Account</li>
</ul>
<h3>Create New Account</h3><hr />
<form action="new" method="post">
<fieldset>
<div class="row">
<div class="form-group col-md-6">
<label for="email" class="control-label">Email</label>
<div>
<input type="text" autocomplete="off" name="email" value="{{ old('email') }}" class="form-control" />
</div>
</div>
<div class="form-group col-md-6">
<label for="username" class="control-label">Username</label>
<div>
<input type="text" autocomplete="off" name="username" value="{{ old('username') }}" class="form-control" />
</div>
</div>
</div>
<div class="row">
<div class="form-group col-md-6">
<label for="name_first" class="control-label">Client First Name</label>
<div>
<input type="text" autocomplete="off" name="name_first" value="{{ old('name_first') }}" class="form-control" />
</div>
</div>
<div class="form-group col-md-6">
<label for="name_last" class="control-label">Client Last Name</label>
<div>
<input type="text" autocomplete="off" name="name_last" value="{{ old('name_last') }}" class="form-control" />
</div>
</div>
<div class="form-group col-md-12">
<label for="root_admin" class="control-label">{{ trans('strings.root_administrator') }}</label>
<div>
<select name="root_admin" class="form-control">
<option value="0">{{ trans('strings.no') }}</option>
<option value="1">{{ trans('strings.yes') }}</option>
</select>
<p class="text-muted"><small>Setting this to 'Yes' gives a user full administrative access.</small></p>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<hr />
<div class="alert alert-info">
<p>Providing a user password is optional. New user emails prompt users to create a password the first time they login. If a password is provided here you will need to find a different method of providing it to the user.</p>
</div>
</div>
<div class="col-md-12">
<div id="gen_pass" class=" alert alert-success" style="display:none;margin-bottom: 10px;"></div>
</div>
<div class="form-group col-md-6">
<label for="pass" class="control-label">Password</label>
<div>
<input type="password" name="password" class="form-control" />
</div>
</div>
<div class="form-group col-md-6">
<label for="pass_2" class="control-label">Password Again</label>
<div>
<input type="password" name="password_confirmation" class="form-control" />
</div>
</div>
</div>
<div class="form-group">
<div>
{!! csrf_field() !!}
<button class="btn btn-primary btn-sm" type="submit">Create Account</button>
<button class="btn btn-default btn-sm" id="gen_pass_bttn" type="button">Generate Password</button>
</div>
</div>
</fieldset>
</form>
</div>
<script>
$(document).ready(function(){
$("#sidebar_links").find("a[href='/admin/account/new']").addClass('active');
$("#gen_pass_bttn").click(function(e){
e.preventDefault();
$.ajax({
type: "GET",
url: "/password-gen/12",
headers: {
'X-CSRF-TOKEN': '{{ csrf_token() }}'
},
success: function(data) {
$("#gen_pass").html('<strong>Generated Password:</strong> ' + data).slideDown();
$('input[name="password"], input[name="password_confirmation"]').val(data);
return false;
}
});
return false;
});
});
$(document).ready(function () {
$('#sidebar_links').find("a[href='/admin/users/new']").addClass('active');
});
</script>
@endsection

View file

@ -1,171 +0,0 @@
{{-- Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com> --}}
{{-- Some Modifications (c) 2015 Dylan Seidt <dylan.seidt@gmail.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. --}}
@extends('layouts.admin')
@section('title')
Viewing User
@endsection
@section('content')
<div class="col-md-12">
<ul class="breadcrumb">
<li><a href="/admin">Admin Controls</a></li>
<li><a href="/admin/users">Accounts</a></li>
<li class="active">{{ $user->email }}</li>
</ul>
<h3 style="margin-bottom: 5px;">Viewing User: {{ $user->email }}</h3>
<p class="text-muted" style="margin: 0 0 -10.5px !important;"><small>Registered {{ (new Carbon($user->created_at))->toRfc1123String() }}</small></p>
<hr />
<div class="row">
<form action="{{ route('admin.users.view', $user->id) }}" method="post">
<div class="col-md-6">
<fieldset>
<div class="form-group">
<label for="email" class="control-label">Email</label>
<div>
<input type="text" name="email" value="{{ $user->email }}" class="form-control">
</div>
</div>
<div class="form-group">
<label for="registered" class="control-label">Username</label>
<div>
<input type="text" name="username" value="{{ $user->username }}" class="form-control">
</div>
</div>
<div class="form-group">
<label for="registered" class="control-label">Client First Name</label>
<div>
<input type="text" name="name_first" value="{{ $user->name_first }}" class="form-control">
</div>
</div>
<div class="form-group">
<label for="registered" class="control-label">Client Last Name</label>
<div>
<input type="text" name="name_last" value="{{ $user->name_last }}" class="form-control">
</div>
</div>
<div class="form-group">
{!! csrf_field() !!}
<input type="submit" value="Update User" class="btn btn-primary btn-sm">
</div>
</fieldset>
</div>
<div class="col-md-6">
<div class="well" style="padding-bottom: 0;">
<div class="alert alert-success" style="display:none;margin-bottom:10px;" id="gen_pass"></div>
<div class="form-group">
<label for="password" class="control-label">Password</label>
<div>
<input type="password" id="password" name="password" class="form-control">
</div>
</div>
<div class="form-group">
<button class="btn btn-default btn-sm" id="gen_pass_bttn" type="button">Generate Password</button>
</div>
</div>
<div class="well" style="padding-bottom: 0;">
<div class="form-group">
<label for="root_admin" class="control-label">Administrator</label>
<div>
<select name="root_admin" class="form-control">
<option value="0">{{ trans('strings.no') }}</option>
<option value="1" @if($user->root_admin)selected="selected"@endif>{{ trans('strings.yes') }}</option>
</select>
<p class="text-muted"><small>Setting this to 'Yes' gives a user full administrative access.</small></p>
</div>
</div>
</div>
</div>
</form>
</div>
<div class="row">
<div class="col-md-12">
<h3>Associated Servers</h3><hr>
@if($user->servers)
<table class="table table-striped table-bordered table-hover">
<thead>
<tr>
<th style="width:2%;"></th>
<th>Identifier</th>
<th>Server Name</th>
<th>Node</th>
<th>Username</th>
<th style="width:10%;"></th>
</tr>
</thead>
<tbody>
@foreach($user->servers as $server)
<tr>
<td><a href="/server/{{ $server->uuidShort }}/"><i class="fa fa-tachometer"></i></a></td>
<td><code>{{ $server->uuidShort }}</code></td>
<td><a href="/admin/servers/view/{{ $server->id }}">{{ $server->name }}</a></td>
<td>{{ $server->node->name }}</td>
<td><code>{{ $server->username }}</code></td>
<td class="centered">@if($server->suspended === 0)<span class="label muted muted-hover label-success">Active</span>@else<span class="label label-warning">Suspended</span>@endif</td>
</td>
@endforeach
</tbody>
</table>
@else
<div class="alert alert-info">There are no servers associated with this account.</div>
@endif
<a href="/admin/servers/new?email={{ $user->email }}"><button type="button" class="btn btn-success btn-sm">Add New Server</button></a>
</div>
</div>
<div class="row">
<div class="col-md-12">
<h3>Delete Account</h3><hr />
<div class="alert alert-danger"><strong>Warning!</strong> There most be no servers associated with this account in order for it to be deleted.</div>
<form action="{{ route('admin.users.view', $user->id) }}" method="POST">
{!! method_field('DELETE') !!}
{!! csrf_field() !!}
<input type="submit" class="btn btn-sm btn-danger pull-right" value="Delete User" />
</form>
</div>
</div>
</div>
<script>
$(document).ready(function(){
$("#sidebar_links").find("a[href='/admin/users']").addClass('active');
$('#delete').click(function() {
if(confirm('{{ trans('base.confirm') }}')) {
$('#delete').load($(this).attr('href'));
}
});
$("#gen_pass_bttn").click(function (event) {
event.preventDefault();
$.ajax({
type: "GET",
url: "/password-gen/12",
headers: {
'X-CSRF-TOKEN': '{{ csrf_token() }}'
},
success: function(data) {
$("#gen_pass").html('You must click <em>Update User</em> to the left for this password to be applied.<br /><br /><strong>Generated Password:</strong> ' + data).slideDown();
$('input[name="password"], input[name="password_confirmation"]').val(data);
return false;
}
});
return false;
});
});
</script>
@endsection