View and Delete Users
This commit implements an interface into the Admin Panel that allows users to be viewed, modified, and deleted.
This commit is contained in:
parent
6b25a163fc
commit
6810375d2b
8 changed files with 268 additions and 3 deletions
|
@ -3,8 +3,10 @@
|
||||||
namespace Pterodactyl\Http\Controllers\Admin;
|
namespace Pterodactyl\Http\Controllers\Admin;
|
||||||
|
|
||||||
use Alert;
|
use Alert;
|
||||||
|
use Mail;
|
||||||
use Pterodactyl\Models\User;
|
use Pterodactyl\Models\User;
|
||||||
use Pterodactyl\Repositories\UserRepository;
|
use Pterodactyl\Repositories\UserRepository;
|
||||||
|
use Pterodactyl\Models\Server;
|
||||||
|
|
||||||
use Pterodactyl\Http\Controllers\Controller;
|
use Pterodactyl\Http\Controllers\Controller;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
@ -38,7 +40,16 @@ class AccountsController extends Controller
|
||||||
|
|
||||||
public function getView(Request $request, $id)
|
public function getView(Request $request, $id)
|
||||||
{
|
{
|
||||||
//
|
return view('admin.accounts.view', ['user' => User::findOrFail($id), 'servers' => Server::where('owner', $id)->first()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDelete(Request $request, $id)
|
||||||
|
{
|
||||||
|
$user = new UserRepository;
|
||||||
|
$user->delete($id);
|
||||||
|
|
||||||
|
Alert::success('An account has been successfully deleted.')->flash();
|
||||||
|
return redirect()->route('admin.accounts');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function postNew(Request $request)
|
public function postNew(Request $request)
|
||||||
|
@ -65,4 +76,43 @@ class AccountsController extends Controller
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function postUpdate(Request $request)
|
||||||
|
{
|
||||||
|
$this->validate($request, [
|
||||||
|
'email' => 'required|email|unique:users,email,'.$request->input('user'),
|
||||||
|
'root_admin' => 'required',
|
||||||
|
'password' => 'required_with:password_confirmation',
|
||||||
|
'password_confirmation' => 'required_with:password'
|
||||||
|
]);
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
$users = new UserRepository;
|
||||||
|
$user = [];
|
||||||
|
|
||||||
|
$user['email'] = $request->input('email');
|
||||||
|
$user['root_admin'] = $request->input('root_admin');
|
||||||
|
|
||||||
|
if(!empty($request->input('password'))) {
|
||||||
|
$user['password'] = $request->input('password');
|
||||||
|
}
|
||||||
|
|
||||||
|
$users->update($request->input('user'), $user);
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Alert::danger('An error occured while attempting to update a user. Please check the logs or try again.')->flash();
|
||||||
|
return redirect()->route('admin.accounts.view', ['id' => $request->input('user')]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if($request->input('email_user')) {
|
||||||
|
Mail::send('emails.new_password', ['user' => User::findOrFail($request->input('user')), 'password' => $request->input('password')], function($message) use ($request) {
|
||||||
|
$message->to($request->input('email'))->subject('Pterodactyl - Admin Reset Password');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Alert::success('A user was successfully updated.')->flash();
|
||||||
|
return redirect()->route('admin.accounts.view', ['id' => $request->input('user')]);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,11 +12,15 @@ class AdminRoutes {
|
||||||
|
|
||||||
// Account Routes
|
// Account Routes
|
||||||
$router->group(['prefix' => 'accounts'], function ($server) use ($router) {
|
$router->group(['prefix' => 'accounts'], function ($server) use ($router) {
|
||||||
$router->get('/', [ 'as' => 'admin.accounts', 'uses' => 'Admin\AccountsController@getIndex' ]);
|
|
||||||
$router->get('/view/{id}', [ 'as' => 'admin.accounts.view', 'uses' => 'Admin\AccountsController@getView' ]);
|
|
||||||
|
|
||||||
$router->get('/new', [ 'as' => 'admin.accounts.new', 'uses' => 'Admin\AccountsController@getNew' ]);
|
$router->get('/new', [ 'as' => 'admin.accounts.new', 'uses' => 'Admin\AccountsController@getNew' ]);
|
||||||
$router->post('/new', [ 'as' => 'admin.accounts.new', 'uses' => 'Admin\AccountsController@postNew' ]);
|
$router->post('/new', [ 'as' => 'admin.accounts.new', 'uses' => 'Admin\AccountsController@postNew' ]);
|
||||||
|
|
||||||
|
$router->get('/', [ 'as' => 'admin.accounts', 'uses' => 'Admin\AccountsController@getIndex' ]);
|
||||||
|
$router->get('/view/{id}', [ 'as' => 'admin.accounts.view', 'uses' => 'Admin\AccountsController@getView' ]);
|
||||||
|
|
||||||
|
$router->post('/update', [ 'as' => 'admin.accounts.update', 'uses' => 'Admin\AccountsController@postUpdate' ]);
|
||||||
|
$router->get('/delete/{id}', [ 'as' => 'admin.accounts.delete', 'uses' => 'Admin\AccountsController@getDelete' ]);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Server Routes
|
// Server Routes
|
||||||
|
|
|
@ -41,4 +41,36 @@ class UserRepository
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates a user on the panel. Returns true if the update was successful.
|
||||||
|
*
|
||||||
|
* @param string $username
|
||||||
|
* @param string $email
|
||||||
|
* @param string $password An unhashed version of the user's password.
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function update($id, $user)
|
||||||
|
{
|
||||||
|
if(array_key_exists('password', $user)) {
|
||||||
|
$user['password'] = Hash::make($user['password']);
|
||||||
|
}
|
||||||
|
|
||||||
|
User::where('id', $id)->update($user);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes a user on the panel. Returns true if the deletion was successful.
|
||||||
|
*
|
||||||
|
* @param string $username
|
||||||
|
* @param string $email
|
||||||
|
* @param string $password An unhashed version of the user's password.
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function delete($id)
|
||||||
|
{
|
||||||
|
User::destroy($id);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ return [
|
||||||
|
|
||||||
'validation_error' => 'An error occured while validating the data you submitted:',
|
'validation_error' => 'An error occured while validating the data you submitted:',
|
||||||
|
|
||||||
|
'confirm' => 'Are you sure?',
|
||||||
'failed' => 'These credentials do not match our records.',
|
'failed' => 'These credentials do not match our records.',
|
||||||
'throttle' => 'Too many login attempts. Please try again in :seconds seconds.',
|
'throttle' => 'Too many login attempts. Please try again in :seconds seconds.',
|
||||||
'view_as_admin' => 'You are viewing this server listing as an admin. As such, all servers installed on the system are displayed. Any servers that you are set as the owner of are marked with a blue dot to the left of their name.',
|
'view_as_admin' => 'You are viewing this server listing as an admin. As such, all servers installed on the system are displayed. Any servers that you are set as the owner of are marked with a blue dot to the left of their name.',
|
||||||
|
@ -21,6 +22,7 @@ return [
|
||||||
'no_servers' => 'You do not currently have any servers listed on your account.',
|
'no_servers' => 'You do not currently have any servers listed on your account.',
|
||||||
'form_error' => 'The following errors were encountered while trying to process this request.',
|
'form_error' => 'The following errors were encountered while trying to process this request.',
|
||||||
'password_req' => 'Passwords must meet the following requirements: at least one uppercase character, one lowercase character, one digit, and be at least 8 characters in length.',
|
'password_req' => 'Passwords must meet the following requirements: at least one uppercase character, one lowercase character, one digit, and be at least 8 characters in length.',
|
||||||
|
'root_administrator' => 'Setting this to "Yes" gives a user full administrative access to PufferPanel.',
|
||||||
|
|
||||||
'account' => [
|
'account' => [
|
||||||
'totp_header' => 'Two-Factor Authentication',
|
'totp_header' => 'Two-Factor Authentication',
|
||||||
|
@ -35,6 +37,9 @@ return [
|
||||||
'totp_enabled' => 'Your account has been enabled with TOTP verification. Please click the close button on this box to finish.',
|
'totp_enabled' => 'Your account has been enabled with TOTP verification. Please click the close button on this box to finish.',
|
||||||
'totp_enabled_error' => 'The TOTP token provided was unable to be verified. Please try again.',
|
'totp_enabled_error' => 'The TOTP token provided was unable to be verified. Please try again.',
|
||||||
|
|
||||||
|
'email_password' => 'Email Password',
|
||||||
|
'update_user' => 'Update User',
|
||||||
|
'delete_user' => 'Delete User',
|
||||||
'update_email' => 'Update Email',
|
'update_email' => 'Update Email',
|
||||||
'new_email' => 'New Email',
|
'new_email' => 'New Email',
|
||||||
'new_password' => 'New Password',
|
'new_password' => 'New Password',
|
||||||
|
|
|
@ -14,6 +14,7 @@ return [
|
||||||
'socket_status_crashed' => 'This server has been detected as CRASHED.',
|
'socket_status_crashed' => 'This server has been detected as CRASHED.',
|
||||||
],
|
],
|
||||||
'index' => [
|
'index' => [
|
||||||
|
'add_new' => 'Add New Server',
|
||||||
'memory_use' => 'Memory Usage',
|
'memory_use' => 'Memory Usage',
|
||||||
'cpu_use' => 'CPU Usage',
|
'cpu_use' => 'CPU Usage',
|
||||||
'xaxis' => 'Time (2s Increments)',
|
'xaxis' => 'Time (2s Increments)',
|
||||||
|
|
|
@ -27,5 +27,9 @@ return [
|
||||||
'submit' => 'Submit',
|
'submit' => 'Submit',
|
||||||
'current_password' => 'Current Password',
|
'current_password' => 'Current Password',
|
||||||
'again' => 'Again',
|
'again' => 'Again',
|
||||||
|
'registered' => 'Registered',
|
||||||
|
'root_administrator' => 'Root Administrator',
|
||||||
|
'yes' => 'Yes',
|
||||||
|
'no' => 'No'
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|
155
resources/views/admin/accounts/view.blade.php
Normal file
155
resources/views/admin/accounts/view.blade.php
Normal file
|
@ -0,0 +1,155 @@
|
||||||
|
@extends('layouts.admin')
|
||||||
|
|
||||||
|
@section('title')
|
||||||
|
Viewing User
|
||||||
|
@endsection
|
||||||
|
|
||||||
|
@section('content')
|
||||||
|
<div class="col-md-9">
|
||||||
|
<ul class="breadcrumb">
|
||||||
|
<li><a href="/admin">Admin Controls</a></li>
|
||||||
|
<li><a href="/admin/accounts">Accounts</a></li>
|
||||||
|
<li class="active">{{ $user->id }}</li>
|
||||||
|
</ul>
|
||||||
|
@if (count($errors) > 0)
|
||||||
|
<div class="alert alert-danger">
|
||||||
|
<strong>{{ trans('strings.whoops') }}!</strong> {{ trans('auth.errorencountered') }}<br><br>
|
||||||
|
<ul>
|
||||||
|
@foreach ($errors->all() as $error)
|
||||||
|
<li>{{ $error }}</li>
|
||||||
|
@endforeach
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
@foreach (Alert::getMessages() as $type => $messages)
|
||||||
|
@foreach ($messages as $message)
|
||||||
|
<div class="alert alert-{{ $type }} alert-dismissable" role="alert">
|
||||||
|
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||||
|
{!! $message !!}
|
||||||
|
</div>
|
||||||
|
@endforeach
|
||||||
|
@endforeach
|
||||||
|
<h3>Viewing User: {{ $user->email }}</h3><hr />
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<form action="/admin/accounts/update" method="post">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<fieldset>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="email" class="control-label">{{ trans('strings.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">{{ trans('strings.registered') }}</label>
|
||||||
|
<div>
|
||||||
|
<input type="text" name="registered" value="{{ $user->created_at }}" readonly="readonly" class="form-control">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<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" @if($user->root_admin)selected="selected"@endif>{{ trans('strings.yes') }}</option>
|
||||||
|
</select>
|
||||||
|
<p><small class="text-muted"><em><strong><i class="fa fa-warning"></i></strong> {{ trans('base.root_administrator') }}</em></small></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<input type="hidden" name="user" value="{{ $user->id }}">
|
||||||
|
{!! csrf_field() !!}
|
||||||
|
<input type="submit" value="{{ trans('base.account.update_user') }}" class="btn btn-primary btn-sm">
|
||||||
|
<a href="/admin/accounts/delete/{{ $user->id }}">
|
||||||
|
<button id="delete" type="button" class="btn btn-sm btn-danger" value="{{ trans('base.account.delete_user') }}">{{ trans('base.account.delete_user') }}</button>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="well" style="padding-bottom: 0;">
|
||||||
|
<h4 class="nopad">{{ trans('base.account.update_pass') }}</h5><hr>
|
||||||
|
<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">{{ trans('strings.password') }}</label>
|
||||||
|
<div>
|
||||||
|
<input type="password" id="password" name="password" class="form-control">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="password_confirmation" class="control-label">{{ trans('auth.confirmpassword') }}</label>
|
||||||
|
<div>
|
||||||
|
<input type="password" id="password_confirmation" name="password_confirmation" class="form-control">
|
||||||
|
<div class="checkbox">
|
||||||
|
<label><input type="checkbox" name="email_user" value="1">{{ trans('base.account.email_password') }}</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button class="btn btn-default btn-sm" id="gen_pass_bttn" type="button">Generate Password</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<h3>Associated Servers</h3><hr>
|
||||||
|
@if($servers)
|
||||||
|
<table class="table table-striped table-bordered table-hover">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th style="width:2%;"></th>
|
||||||
|
<th>Server Name</th>
|
||||||
|
<th>Node</th>
|
||||||
|
<th>Connection</th>
|
||||||
|
<th style="width:10%;"></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
@foreach($servers as $server)
|
||||||
|
<tr>
|
||||||
|
<td><a href="/server/{{ $server->uuidShort }}"><i class="fa fa-tachometer"></i></a></td>
|
||||||
|
<td><a href="/admin/server/view/{{ $server->id }}">{{ $server->name }}</a></td>
|
||||||
|
<td>{{ $server->node_name }}</td>
|
||||||
|
<td>{{ $server->server_ip }}:{{ $server->server_port }}</td>
|
||||||
|
<td>@if($server->active)<span class="label label-success">Enabled</span>@else<span class="label label-danger">Disabled</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">{{ trans('server.index.add_new') }}</button></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
$(document).ready(function(){
|
||||||
|
$("#sidebar_links").find("a[href='/admin/accounts']").addClass('active');
|
||||||
|
$('#delete').click(function() {
|
||||||
|
if(confirm('{{ trans('base.confirm') }}')) {
|
||||||
|
$('#delete').load($(this).attr('href'));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
$("#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;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
@endsection
|
14
resources/views/emails/new_password.blade.php
Normal file
14
resources/views/emails/new_password.blade.php
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Pterodactyl - Admin Reset Password</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<center><h1>Pterodactyl - Admin Reset Password</h1></center>
|
||||||
|
<p>Hello there! You are receiving this email because an admin has reset the password on your Pterodactyl account.</p>
|
||||||
|
<p><strong>Login:</strong> <a href="{{ config('app.url') }}/auth/login">{{ config('app.url') }}/auth/login</a><br>
|
||||||
|
<strong>Email:</strong> {{ $user->email }}<br>
|
||||||
|
<strong>Password:</strong> {{ $password }}</p>
|
||||||
|
<p>Thanks,<br>Pterodactyl</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Reference in a new issue