diff --git a/app/Http/Controllers/Server/TaskController.php b/app/Http/Controllers/Server/TaskController.php index 7c6140379..a5cd01512 100644 --- a/app/Http/Controllers/Server/TaskController.php +++ b/app/Http/Controllers/Server/TaskController.php @@ -26,6 +26,7 @@ namespace Pterodactyl\Http\Controllers\Server; use Log; use Alert; +use Javascript; use Pterodactyl\Models; use Illuminate\Http\Request; use Pterodactyl\Repositories; @@ -44,14 +45,20 @@ class TaskController extends Controller { $server = Models\Server::getByUUID($uuid); $this->authorize('list-tasks', $server); + $node = Models\Node::find($server->node); + + Javascript::put([ + 'server' => collect($server->makeVisible('daemonSecret'))->only(['uuid', 'uuidShort', 'daemonSecret', 'username']), + 'node' => collect($node)->only('fqdn', 'scheme', 'daemonListen'), + ]); return view('server.tasks.index', [ 'server' => $server, - 'node' => Models\Node::findOrFail($server->node), + 'node' => $node, 'tasks' => Models\Task::where('server', $server->id)->get(), 'actions' => [ - 'command' => 'Send Command', - 'power' => 'Set Power Status', + 'command' => trans('server.tasks.actions.command'), + 'power' => trans('server.tasks.actions.power'), ], ]); } @@ -60,10 +67,15 @@ class TaskController extends Controller { $server = Models\Server::getByUUID($uuid); $this->authorize('create-task', $server); + $node = Models\Node::find($server->node); + Javascript::put([ + 'server' => collect($server->makeVisible('daemonSecret'))->only(['uuid', 'uuidShort', 'daemonSecret', 'username']), + 'node' => collect($node)->only('fqdn', 'scheme', 'daemonListen'), + ]); return view('server.tasks.new', [ 'server' => $server, - 'node' => Models\Node::findOrFail($server->node), + 'node' => $node, ]); } @@ -77,8 +89,9 @@ class TaskController extends Controller $repo->create($server->id, $request->except([ '_token', ])); + return redirect()->route('server.tasks', $uuid); } catch (DisplayValidationException $ex) { - return redirect()->route('server.tasks', $uuid)->withErrors(json_decode($ex->getMessage()))->withInput(); + return redirect()->route('server.tasks.new', $uuid)->withErrors(json_decode($ex->getMessage()))->withInput(); } catch (DisplayException $ex) { Alert::danger($ex->getMessage())->flash(); } catch (\Exception $ex) { @@ -86,19 +99,7 @@ class TaskController extends Controller Alert::danger('An unknown error occured while attempting to create this task.')->flash(); } - return redirect()->route('server.tasks', $uuid); - } - - public function getView(Request $request, $uuid, $id) - { - $server = Models\Server::getByUUID($uuid); - $this->authorize('view-task', $server); - - return view('server.tasks.view', [ - 'server' => $server, - 'node' => Models\Node::findOrFail($server->node), - 'task' => Models\Task::where('id', $id)->where('server', $server->id)->firstOrFail(), - ]); + return redirect()->route('server.tasks.new', $uuid); } public function deleteTask(Request $request, $uuid, $id) diff --git a/public/themes/pterodactyl/js/frontend/tasks.js b/public/themes/pterodactyl/js/frontend/tasks.js new file mode 100644 index 000000000..c990559e7 --- /dev/null +++ b/public/themes/pterodactyl/js/frontend/tasks.js @@ -0,0 +1,102 @@ +// Copyright (c) 2015 - 2016 Dane Everitt +// +// 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. +(function initTaskFunctions() { + $('[data-action="delete-task"]').click(function (event) { + var self = $(this); + swal({ + type: 'error', + title: 'Delete Task?', + text: 'Are you sure you want to delete this task? There is no undo.', + showCancelButton: true, + allowOutsideClick: true, + closeOnConfirm: false, + confirmButtonText: 'Delete Task', + confirmButtonColor: '#d9534f', + showLoaderOnConfirm: true + }, function () { + $.ajax({ + method: 'DELETE', + url: Router.route('server.tasks.delete', { + server: Pterodactyl.server.uuidShort, + id: self.data('id'), + }), + headers: { + 'X-CSRF-TOKEN': $('meta[name="_token"]').attr('content'), + } + }).done(function (data) { + swal({ + type: 'success', + title: '', + text: 'Task has been deleted.' + }); + self.parent().parent().slideUp(); + }).fail(function (jqXHR) { + console.error(jqXHR); + swal({ + type: 'error', + title: 'Whoops!', + text: 'An error occured while attempting to delete this task.' + }); + }); + }); + }); + $('[data-action="toggle-task"]').click(function (event) { + var self = $(this); + swal({ + type: 'info', + title: 'Toggle Task', + text: 'This will toggle the selected task.', + showCancelButton: true, + allowOutsideClick: true, + closeOnConfirm: false, + confirmButtonText: 'Continue', + showLoaderOnConfirm: true + }, function () { + $.ajax({ + method: 'POST', + url: Router.route('server.tasks.toggle', { + server: Pterodactyl.server.uuidShort, + id: self.data('id'), + }), + headers: { + 'X-CSRF-TOKEN': $('meta[name="_token"]').attr('content'), + } + }).done(function (data) { + swal({ + type: 'success', + title: '', + text: 'Task has been toggled.' + }); + if (data.status !== 1) { + self.parent().parent().addClass('muted muted-hover'); + } else { + self.parent().parent().removeClass('muted muted-hover'); + } + }).fail(function (jqXHR) { + console.error(jqXHR); + swal({ + type: 'error', + title: 'Whoops!', + text: 'An error occured while attempting to toggle this task.' + }); + }); + }); + }); +})(); diff --git a/resources/lang/en/server.php b/resources/lang/en/server.php index bfb304f55..f629c52d3 100644 --- a/resources/lang/en/server.php +++ b/resources/lang/en/server.php @@ -6,6 +6,37 @@ return [ 'header' => 'Server Console', 'header_sub' => 'Control your server in real time.', ], + 'tasks' => [ + 'header' => 'Scheduled Tasks', + 'header_sub' => 'Automate your server.', + 'current' => 'Current Scheduled Tasks', + 'actions' => [ + 'command' => 'Send Command', + 'power' => 'Send Power Toggle', + ], + 'new_task' => 'Add New Task', + 'toggle' => 'Toggle Status', + 'new' => [ + 'header' => 'New Task', + 'header_sub' => 'Create a new scheduled task for this server.', + 'day_of_week' => 'Day of Week', + 'custom' => 'Custom Value', + 'day_of_month' => 'Day of Month', + 'hour' => 'Hour', + 'minute' => 'Minute', + 'sun' => 'Sunday', + 'mon' => 'Monday', + 'tues' => 'Tuesday', + 'wed' => 'Wednesday', + 'thurs' => 'Thursday', + 'fri' => 'Friday', + 'sat' => 'Saturday', + 'submit' => 'Create Task', + 'type' => 'Task Type', + 'payload' => 'Task Payload', + 'payload_help' => 'For example, if you selected Send Command enter the command here. If you selected Send Power Option put the power action here (e.g. restart).', + ], + ], 'users' => [ 'header' => 'Manage Users', 'header_sub' => 'Control who can access your server.', diff --git a/resources/lang/en/strings.php b/resources/lang/en/strings.php index 324f956a9..8aeaf6ffa 100644 --- a/resources/lang/en/strings.php +++ b/resources/lang/en/strings.php @@ -51,4 +51,12 @@ return [ 'none' => 'None', 'cancel' => 'Cancel', 'created_at' => 'Created At', + 'action' => 'Action', + 'data' => 'Data', + 'queued' => 'Queued', + 'last_run' => 'Last Run', + 'next_run' => 'Next Run', + 'yes' => 'Yes', + 'no' => 'No', + 'delete' => 'Delete', ]; diff --git a/resources/themes/pterodactyl/layouts/master.blade.php b/resources/themes/pterodactyl/layouts/master.blade.php index 260a1a6a3..2a548e36a 100644 --- a/resources/themes/pterodactyl/layouts/master.blade.php +++ b/resources/themes/pterodactyl/layouts/master.blade.php @@ -166,11 +166,15 @@ Subusers -
  • +
  • @lang('navigation.server.task_management') - 4 + {{ \Pterodactyl\Models\Task::select('id')->where('server', $server->id)->where('active', 1)->count() }}
  • diff --git a/resources/themes/pterodactyl/server/tasks/index.blade.php b/resources/themes/pterodactyl/server/tasks/index.blade.php new file mode 100644 index 000000000..dc6e2b239 --- /dev/null +++ b/resources/themes/pterodactyl/server/tasks/index.blade.php @@ -0,0 +1,99 @@ +{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} + +{{-- 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.master') + +@section('title') + @lang('server.tasks.header') +@endsection + +@section('content-header') +

    @lang('server.tasks.header')@lang('server.tasks.header_sub')

    + +@endsection + +@section('content') +
    +
    +
    +
    +

    @lang('server.tasks.current')

    +
    +
    + + + + + + + + + + + + @foreach($tasks as $task) + active === 0)class="muted muted-hover"@endif> + + + + + + @can('delete-task', $server) + + @endcan + @can('toggle-task', $server) + + @endcan + + @endforeach + + +
    @lang('strings.action')@lang('strings.data')@lang('strings.queued')@lang('strings.last_run')@lang('strings.next_run')
    {{ $actions[$task->action] }}{{ $task->data }} + @if ($task->queued) + @lang('strings.yes') + @else + @lang('strings.no') + @endif + {{ Carbon::parse($task->last_run)->toDayDateTimeString() }}
    ({{ Carbon::parse($task->last_run)->diffForHumans() }})
    + @if($task->active !== 0) + {{ Carbon::parse($task->next_run)->toDayDateTimeString() }}
    ({{ Carbon::parse($task->next_run)->diffForHumans() }}) + @else + n/a + @endif +
    +
    + +
    +
    +
    +@endsection + +@section('footer-scripts') + @parent + {!! Theme::js('js/frontend/server.socket.js') !!} + {!! Theme::js('js/frontend/tasks.js') !!} +@endsection diff --git a/resources/themes/pterodactyl/server/tasks/new.blade.php b/resources/themes/pterodactyl/server/tasks/new.blade.php new file mode 100644 index 000000000..03db43b1f --- /dev/null +++ b/resources/themes/pterodactyl/server/tasks/new.blade.php @@ -0,0 +1,208 @@ +{{-- Copyright (c) 2015 - 2016 Dane Everitt --}} + +{{-- 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.master') + +@section('title') + @lang('server.tasks.new.header') +@endsection + +@section('scripts') + {{-- This has to be loaded before the AdminLTE theme to avoid dropdown issues. --}} + {!! Theme::css('vendor/select2/select2.min.css') !!} + @parent +@endsection + +@section('content-header') +

    @lang('server.tasks.new.header')@lang('server.tasks.new.header_sub')

    + +@endsection + +@section('content') +
    +
    +
    +
    +
    +

    @lang('server.tasks.new.day_of_week')

    +
    +
    +
    +
    +
    + +
    +
    +
    + +
    + +
    +
    +
    +
    +
    +
    +
    +
    +
    +

    @lang('server.tasks.new.day_of_month')

    +
    +
    +
    +
    +
    + +
    +
    +
    + +
    + +
    +
    +
    +
    +
    +
    +
    +
    +
    +

    @lang('server.tasks.new.hour')

    +
    +
    +
    +
    +
    + +
    +
    +
    + +
    + +
    +
    +
    +
    +
    +
    +
    +
    +
    +

    @lang('server.tasks.new.minute')

    +
    +
    +
    +
    +
    + +
    +
    +
    + +
    + +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + +
    + +
    +
    +
    + +
    + + @lang('server.tasks.new.payload_help') +
    +
    +
    +
    + +
    +
    +
    + +@endsection + +@section('footer-scripts') + @parent + {!! Theme::js('js/frontend/server.socket.js') !!} + {!! Theme::js('vendor/select2/select2.full.min.js') !!} + +@endsection