Merge pull request #17 from DDynamic/feature-view_accounts

View and Delete Users
This commit is contained in:
Dane Everitt 2016-01-02 12:39:08 -05:00
commit 9d6563f8de
8 changed files with 268 additions and 3 deletions

View file

@ -3,8 +3,10 @@
namespace Pterodactyl\Http\Controllers\Admin;
use Alert;
use Mail;
use Pterodactyl\Models\User;
use Pterodactyl\Repositories\UserRepository;
use Pterodactyl\Models\Server;
use Pterodactyl\Http\Controllers\Controller;
use Illuminate\Http\Request;
@ -38,7 +40,16 @@ class AccountsController extends Controller
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)
@ -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')]);
}
}

View file

@ -12,11 +12,15 @@ class AdminRoutes {
// Account Routes
$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->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

View file

@ -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;
}
}

View file

@ -14,6 +14,7 @@ return [
'validation_error' => 'An error occured while validating the data you submitted:',
'confirm' => 'Are you sure?',
'failed' => 'These credentials do not match our records.',
'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.',
@ -21,6 +22,7 @@ return [
'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.',
'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' => [
'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_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',
'new_email' => 'New Email',
'new_password' => 'New Password',

View file

@ -14,6 +14,7 @@ return [
'socket_status_crashed' => 'This server has been detected as CRASHED.',
],
'index' => [
'add_new' => 'Add New Server',
'memory_use' => 'Memory Usage',
'cpu_use' => 'CPU Usage',
'xaxis' => 'Time (2s Increments)',

View file

@ -27,5 +27,9 @@ return [
'submit' => 'Submit',
'current_password' => 'Current Password',
'again' => 'Again',
'registered' => 'Registered',
'root_administrator' => 'Root Administrator',
'yes' => 'Yes',
'no' => 'No'
];

View 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">&times;</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

View 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>