Skip to content

Commit 9d6563f

Browse files
committed
Merge pull request pterodactyl#17 from DDynamic/feature-view_accounts
View and Delete Users
2 parents 6b25a16 + 6810375 commit 9d6563f

File tree

8 files changed

+268
-3
lines changed

8 files changed

+268
-3
lines changed

app/Http/Controllers/Admin/AccountsController.php

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@
33
namespace Pterodactyl\Http\Controllers\Admin;
44

55
use Alert;
6+
use Mail;
67
use Pterodactyl\Models\User;
78
use Pterodactyl\Repositories\UserRepository;
9+
use Pterodactyl\Models\Server;
810

911
use Pterodactyl\Http\Controllers\Controller;
1012
use Illuminate\Http\Request;
@@ -38,7 +40,16 @@ public function getNew(Request $request)
3840

3941
public function getView(Request $request, $id)
4042
{
41-
//
43+
return view('admin.accounts.view', ['user' => User::findOrFail($id), 'servers' => Server::where('owner', $id)->first()]);
44+
}
45+
46+
public function getDelete(Request $request, $id)
47+
{
48+
$user = new UserRepository;
49+
$user->delete($id);
50+
51+
Alert::success('An account has been successfully deleted.')->flash();
52+
return redirect()->route('admin.accounts');
4253
}
4354

4455
public function postNew(Request $request)
@@ -65,4 +76,43 @@ public function postNew(Request $request)
6576

6677
}
6778

79+
public function postUpdate(Request $request)
80+
{
81+
$this->validate($request, [
82+
'email' => 'required|email|unique:users,email,'.$request->input('user'),
83+
'root_admin' => 'required',
84+
'password' => 'required_with:password_confirmation',
85+
'password_confirmation' => 'required_with:password'
86+
]);
87+
88+
try {
89+
90+
$users = new UserRepository;
91+
$user = [];
92+
93+
$user['email'] = $request->input('email');
94+
$user['root_admin'] = $request->input('root_admin');
95+
96+
if(!empty($request->input('password'))) {
97+
$user['password'] = $request->input('password');
98+
}
99+
100+
$users->update($request->input('user'), $user);
101+
102+
} catch (\Exception $e) {
103+
Alert::danger('An error occured while attempting to update a user. Please check the logs or try again.')->flash();
104+
return redirect()->route('admin.accounts.view', ['id' => $request->input('user')]);
105+
}
106+
107+
if($request->input('email_user')) {
108+
Mail::send('emails.new_password', ['user' => User::findOrFail($request->input('user')), 'password' => $request->input('password')], function($message) use ($request) {
109+
$message->to($request->input('email'))->subject('Pterodactyl - Admin Reset Password');
110+
});
111+
}
112+
113+
Alert::success('A user was successfully updated.')->flash();
114+
return redirect()->route('admin.accounts.view', ['id' => $request->input('user')]);
115+
116+
}
117+
68118
}

app/Http/Routes/AdminRoutes.php

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,15 @@ public function map(Router $router) {
1212

1313
// Account Routes
1414
$router->group(['prefix' => 'accounts'], function ($server) use ($router) {
15-
$router->get('/', [ 'as' => 'admin.accounts', 'uses' => 'Admin\AccountsController@getIndex' ]);
16-
$router->get('/view/{id}', [ 'as' => 'admin.accounts.view', 'uses' => 'Admin\AccountsController@getView' ]);
1715

1816
$router->get('/new', [ 'as' => 'admin.accounts.new', 'uses' => 'Admin\AccountsController@getNew' ]);
1917
$router->post('/new', [ 'as' => 'admin.accounts.new', 'uses' => 'Admin\AccountsController@postNew' ]);
18+
19+
$router->get('/', [ 'as' => 'admin.accounts', 'uses' => 'Admin\AccountsController@getIndex' ]);
20+
$router->get('/view/{id}', [ 'as' => 'admin.accounts.view', 'uses' => 'Admin\AccountsController@getView' ]);
21+
22+
$router->post('/update', [ 'as' => 'admin.accounts.update', 'uses' => 'Admin\AccountsController@postUpdate' ]);
23+
$router->get('/delete/{id}', [ 'as' => 'admin.accounts.delete', 'uses' => 'Admin\AccountsController@getDelete' ]);
2024
});
2125

2226
// Server Routes

app/Repositories/UserRepository.php

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,4 +41,36 @@ public function create($username, $email, $password)
4141

4242
}
4343

44+
/**
45+
* Updates a user on the panel. Returns true if the update was successful.
46+
*
47+
* @param string $username
48+
* @param string $email
49+
* @param string $password An unhashed version of the user's password.
50+
* @return boolean
51+
*/
52+
public function update($id, $user)
53+
{
54+
if(array_key_exists('password', $user)) {
55+
$user['password'] = Hash::make($user['password']);
56+
}
57+
58+
User::where('id', $id)->update($user);
59+
return true;
60+
}
61+
62+
/**
63+
* Deletes a user on the panel. Returns true if the deletion was successful.
64+
*
65+
* @param string $username
66+
* @param string $email
67+
* @param string $password An unhashed version of the user's password.
68+
* @return boolean
69+
*/
70+
public function delete($id)
71+
{
72+
User::destroy($id);
73+
return true;
74+
}
75+
4476
}

resources/lang/en/base.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,15 @@
1414

1515
'validation_error' => 'An error occured while validating the data you submitted:',
1616

17+
'confirm' => 'Are you sure?',
1718
'failed' => 'These credentials do not match our records.',
1819
'throttle' => 'Too many login attempts. Please try again in :seconds seconds.',
1920
'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.',
2021
'server_name' => 'Server Name',
2122
'no_servers' => 'You do not currently have any servers listed on your account.',
2223
'form_error' => 'The following errors were encountered while trying to process this request.',
2324
'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.',
25+
'root_administrator' => 'Setting this to "Yes" gives a user full administrative access to PufferPanel.',
2426

2527
'account' => [
2628
'totp_header' => 'Two-Factor Authentication',
@@ -35,6 +37,9 @@
3537
'totp_enabled' => 'Your account has been enabled with TOTP verification. Please click the close button on this box to finish.',
3638
'totp_enabled_error' => 'The TOTP token provided was unable to be verified. Please try again.',
3739

40+
'email_password' => 'Email Password',
41+
'update_user' => 'Update User',
42+
'delete_user' => 'Delete User',
3843
'update_email' => 'Update Email',
3944
'new_email' => 'New Email',
4045
'new_password' => 'New Password',

resources/lang/en/server.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
'socket_status_crashed' => 'This server has been detected as CRASHED.',
1515
],
1616
'index' => [
17+
'add_new' => 'Add New Server',
1718
'memory_use' => 'Memory Usage',
1819
'cpu_use' => 'CPU Usage',
1920
'xaxis' => 'Time (2s Increments)',

resources/lang/en/strings.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,5 +27,9 @@
2727
'submit' => 'Submit',
2828
'current_password' => 'Current Password',
2929
'again' => 'Again',
30+
'registered' => 'Registered',
31+
'root_administrator' => 'Root Administrator',
32+
'yes' => 'Yes',
33+
'no' => 'No'
3034

3135
];
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
@extends('layouts.admin')
2+
3+
@section('title')
4+
Viewing User
5+
@endsection
6+
7+
@section('content')
8+
<div class="col-md-9">
9+
<ul class="breadcrumb">
10+
<li><a href="/admin">Admin Controls</a></li>
11+
<li><a href="/admin/accounts">Accounts</a></li>
12+
<li class="active">{{ $user->id }}</li>
13+
</ul>
14+
@if (count($errors) > 0)
15+
<div class="alert alert-danger">
16+
<strong>{{ trans('strings.whoops') }}!</strong> {{ trans('auth.errorencountered') }}<br><br>
17+
<ul>
18+
@foreach ($errors->all() as $error)
19+
<li>{{ $error }}</li>
20+
@endforeach
21+
</ul>
22+
</div>
23+
@endif
24+
@foreach (Alert::getMessages() as $type => $messages)
25+
@foreach ($messages as $message)
26+
<div class="alert alert-{{ $type }} alert-dismissable" role="alert">
27+
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>
28+
{!! $message !!}
29+
</div>
30+
@endforeach
31+
@endforeach
32+
<h3>Viewing User: {{ $user->email }}</h3><hr />
33+
<div class="row">
34+
<div class="col-md-12">
35+
<form action="/admin/accounts/update" method="post">
36+
<div class="col-md-6">
37+
<fieldset>
38+
<div class="form-group">
39+
<label for="email" class="control-label">{{ trans('strings.email') }}</label>
40+
<div>
41+
<input type="text" name="email" value="{{ $user->email }}" class="form-control">
42+
</div>
43+
</div>
44+
<div class="form-group">
45+
<label for="registered" class="control-label">{{ trans('strings.registered') }}</label>
46+
<div>
47+
<input type="text" name="registered" value="{{ $user->created_at }}" readonly="readonly" class="form-control">
48+
</div>
49+
</div>
50+
<div class="form-group">
51+
<label for="root_admin" class="control-label">{{ trans('strings.root_administrator') }}</label>
52+
<div>
53+
<select name="root_admin" class="form-control">
54+
<option value="0">{{ trans('strings.no') }}</option>
55+
<option value="1" @if($user->root_admin)selected="selected"@endif>{{ trans('strings.yes') }}</option>
56+
</select>
57+
<p><small class="text-muted"><em><strong><i class="fa fa-warning"></i></strong> {{ trans('base.root_administrator') }}</em></small></p>
58+
</div>
59+
</div>
60+
<div class="form-group">
61+
<input type="hidden" name="user" value="{{ $user->id }}">
62+
{!! csrf_field() !!}
63+
<input type="submit" value="{{ trans('base.account.update_user') }}" class="btn btn-primary btn-sm">
64+
<a href="/admin/accounts/delete/{{ $user->id }}">
65+
<button id="delete" type="button" class="btn btn-sm btn-danger" value="{{ trans('base.account.delete_user') }}">{{ trans('base.account.delete_user') }}</button>
66+
</a>
67+
</div>
68+
</fieldset>
69+
</div>
70+
<div class="col-md-6">
71+
<div class="well" style="padding-bottom: 0;">
72+
<h4 class="nopad">{{ trans('base.account.update_pass') }}</h5><hr>
73+
<div class="alert alert-success" style="display:none;margin-bottom:10px;" id="gen_pass"></div>
74+
<div class="form-group">
75+
<label for="password" class="control-label">{{ trans('strings.password') }}</label>
76+
<div>
77+
<input type="password" id="password" name="password" class="form-control">
78+
</div>
79+
</div>
80+
<div class="form-group">
81+
<label for="password_confirmation" class="control-label">{{ trans('auth.confirmpassword') }}</label>
82+
<div>
83+
<input type="password" id="password_confirmation" name="password_confirmation" class="form-control">
84+
<div class="checkbox">
85+
<label><input type="checkbox" name="email_user" value="1">{{ trans('base.account.email_password') }}</label>
86+
</div>
87+
</div>
88+
<button class="btn btn-default btn-sm" id="gen_pass_bttn" type="button">Generate Password</button>
89+
</div>
90+
</div>
91+
</div>
92+
</form>
93+
</div>
94+
</div>
95+
<div class="row">
96+
<div class="col-md-12">
97+
<h3>Associated Servers</h3><hr>
98+
@if($servers)
99+
<table class="table table-striped table-bordered table-hover">
100+
<thead>
101+
<tr>
102+
<th style="width:2%;"></th>
103+
<th>Server Name</th>
104+
<th>Node</th>
105+
<th>Connection</th>
106+
<th style="width:10%;"></th>
107+
</tr>
108+
</thead>
109+
<tbody>
110+
@foreach($servers as $server)
111+
<tr>
112+
<td><a href="/server/{{ $server->uuidShort }}"><i class="fa fa-tachometer"></i></a></td>
113+
<td><a href="/admin/server/view/{{ $server->id }}">{{ $server->name }}</a></td>
114+
<td>{{ $server->node_name }}</td>
115+
<td>{{ $server->server_ip }}:{{ $server->server_port }}</td>
116+
<td>@if($server->active)<span class="label label-success">Enabled</span>@else<span class="label label-danger">Disabled</span>@endif</td>
117+
</td>
118+
@endforeach
119+
</tbody>
120+
</table>
121+
@else
122+
<div class="alert alert-info">There are no servers associated with this account.</div>
123+
@endif
124+
<a href="/admin/servers/new?email={{ $user->email }}"><button type="button" class="btn btn-success btn-sm">{{ trans('server.index.add_new') }}</button></a>
125+
</div>
126+
</div>
127+
</div>
128+
</div>
129+
<script>
130+
$(document).ready(function(){
131+
$("#sidebar_links").find("a[href='/admin/accounts']").addClass('active');
132+
$('#delete').click(function() {
133+
if(confirm('{{ trans('base.confirm') }}')) {
134+
$('#delete').load($(this).attr('href'));
135+
}
136+
});
137+
$("#gen_pass_bttn").click(function(e){
138+
e.preventDefault();
139+
$.ajax({
140+
type: "GET",
141+
url: "/password-gen/12",
142+
headers: {
143+
'X-CSRF-TOKEN': '{{ csrf_token() }}'
144+
},
145+
success: function(data) {
146+
$("#gen_pass").html('<strong>Generated Password:</strong> ' + data).slideDown();
147+
$('input[name="password"], input[name="password_confirmation"]').val(data);
148+
return false;
149+
}
150+
});
151+
return false;
152+
});
153+
});
154+
</script>
155+
@endsection
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
2+
<html>
3+
<head>
4+
<title>Pterodactyl - Admin Reset Password</title>
5+
</head>
6+
<body>
7+
<center><h1>Pterodactyl - Admin Reset Password</h1></center>
8+
<p>Hello there! You are receiving this email because an admin has reset the password on your Pterodactyl account.</p>
9+
<p><strong>Login:</strong> <a href="{{ config('app.url') }}/auth/login">{{ config('app.url') }}/auth/login</a><br>
10+
<strong>Email:</strong> {{ $user->email }}<br>
11+
<strong>Password:</strong> {{ $password }}</p>
12+
<p>Thanks,<br>Pterodactyl</p>
13+
</body>
14+
</html>

0 commit comments

Comments
 (0)