#1: User accounts can now be deleted. The current user account cannot be deleted, or have the admin privileges removed. Accounts can now be activated manually. New user accounts passwords are encrypted correctly before being saved.

This commit is contained in:
Andy Heathershaw 2016-10-03 14:11:24 +01:00
parent 1b86fa1e0e
commit 7783af00b0
10 changed files with 297 additions and 12 deletions

View File

@ -3,7 +3,7 @@
<component name="WebServers">
<option name="servers">
<webServer id="b14a34b0-0127-4886-964a-7be75a2281ac" name="Development" url="http://blue-twilight-dev.andys.eu">
<fileTransfer host="orlando.default.pandy06269.uk0.bigv.io" port="22" rootFolder="/srv/www/blue-twilight-dev" accessType="SFTP">
<fileTransfer host="mickey.andys.eu" port="22" rootFolder="/srv/www/blue-twilight-dev" accessType="SFTP">
<advancedOptions>
<advancedOptions dataProtectionLevel="Private" />
</advancedOptions>

View File

@ -5,19 +5,40 @@ namespace App\Http\Controllers\Admin;
use App\Facade\Theme;
use App\Facade\UserConfig;
use App\User;
use Illuminate\Http\Request;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Auth;
class UserController extends Controller
{
public function delete(Request $request, $id)
{
$this->authorize('admin-access');
$user = User::where('id', intval($id))->first();
if (is_null($user))
{
App::abort(404);
}
if ($user->id == Auth::user()->id)
{
$request->session()->flash('warning', trans('admin.cannot_delete_own_user_account'));
return redirect(route('user.index'));
}
return Theme::render('admin.delete_user', ['user' => $user]);
}
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index()
public function index(Request $request)
{
$this->authorize('admin-access');
@ -25,7 +46,10 @@ class UserController extends Controller
->paginate(UserConfig::get('items_per_page'));
return Theme::render('admin.list_users', [
'users' => $users
'error' => $request->session()->get('error'),
'success' => $request->session()->get('success'),
'users' => $users,
'warning' => $request->session()->get('warning')
]);
}
@ -53,6 +77,7 @@ class UserController extends Controller
$user = new User();
$user->fill($request->only(['name', 'email', 'password']));
$user->password = bcrypt($user->password);
$user->is_activated = true;
$user->is_admin = (strtolower($request->get('is_admin')) == 'on');
$user->save();
@ -79,7 +104,15 @@ class UserController extends Controller
*/
public function edit($id)
{
//
$this->authorize('admin-access');
$user = User::where('id', intval($id))->first();
if (is_null($user))
{
App::abort(404);
}
return Theme::render('admin.edit_user', ['user' => $user]);
}
/**
@ -89,9 +122,47 @@ class UserController extends Controller
* @param int $id
* @return \Illuminate\Http\Response
*/
public function update(Request $request, $id)
public function update(Requests\StoreUserRequest $request, $id)
{
//
$this->authorize('admin-access');
$user = User::where('id', intval($id))->first();
if (is_null($user))
{
App::abort(404);
}
$user->fill($request->only(['name', 'email']));
// Change user's password only if supplied
if (strlen($request->get('password')) > 0)
{
$user->password = bcrypt($request->get('password'));
}
// Prevent the current administrator from removing their admin rights
if (
$user->is_admin &&
$user->id == Auth::user()->id &&
strtolower($request->get('is_admin')) != 'on'
) {
$request->session()->flash('warning', trans('admin.cannot_remove_own_admin'));
}
else
{
$user->is_admin = (strtolower($request->get('is_admin')) == 'on');
}
// Manually activate account if requested
if (strtolower($request->get('is_activated')) == 'on')
{
$user->is_activated = true;
$user->activation_token = null;
}
$user->save();
return redirect(route('user.index'));
}
/**
@ -100,8 +171,38 @@ class UserController extends Controller
* @param int $id
* @return \Illuminate\Http\Response
*/
public function destroy($id)
public function destroy(Request $request, $id)
{
//
$this->authorize('admin-access');
/** @var User $user */
$user = User::where('id', intval($id))->first();
if (is_null($user))
{
App::abort(404);
}
if ($user->id == Auth::user()->id)
{
$request->session()->flash('warning', trans('admin.cannot_delete_own_user_account'));
return redirect(route('user.index'));
}
try
{
$user->delete();
$request->session()->flash('success', trans('admin.user_deletion_successful', [
'name' => $user->name
]));
}
catch (\Exception $ex)
{
$request->session()->flash('error', trans('admin.user_deletion_failed', [
'error_message' => $ex->getMessage(),
'name' => $user->name
]));
}
return redirect(route('user.index'));
}
}

View File

@ -17,6 +17,21 @@ class StoreUserRequest extends FormRequest
return true;
}
protected function getValidatorInstance()
{
$v = parent::getValidatorInstance();
if ($this->method() == 'PUT')
{
$requirements = RegisterController::passwordRequirements();
$v->sometimes('password', $requirements['password'], function($input) {
return (strlen($input->password) > 0 || strlen($input->password_confirmation) > 0);
});
}
return $v;
}
/**
* Get the validation rules that apply to the request.
*
@ -24,6 +39,21 @@ class StoreUserRequest extends FormRequest
*/
public function rules()
{
switch ($this->method())
{
case 'POST':
return RegisterController::passwordRequirements();
case 'PUT':
$userId = intval($this->segment(3));
$requirements = RegisterController::passwordRequirements();
$requirements['email'] = 'required|email|max:255|unique:users,email,' . $userId;
unset($requirements['password']);
return $requirements;
}
return [];
}
}

View File

@ -11,6 +11,8 @@ return [
'album_settings_tab' => 'Settings',
'album_upload_tab' => 'Upload',
'analyse_photos_failed' => 'The following items could not be analysed and were removed:',
'cannot_delete_own_user_account' => 'It is not possible to delete your own user account. Please ask another administrator to delete it for you.',
'cannot_remove_own_admin' => 'You cannot remove your own administrator permissions. Please ask another administrator to remove the administrator permissions for you.',
'create_album' => 'Create a photo album',
'create_album_intro' => 'Photo albums contain individual photographs together in the same way as a physical photo album or memory book.',
'create_album_intro2' => 'Complete the form below to create a photo album.',
@ -26,12 +28,17 @@ return [
'delete_storage' => 'Delete storage location: :name',
'delete_storage_confirm' => 'Are you sure you want to permanently remove this storage location?',
'delete_storage_existing_albums' => 'At least one album is still using the storage location. Please delete all albums before removing the storage location.',
'delete_storage_warning' => 'This is a permanent action that cannot be undone!',
'delete_storage_warning' => 'This is a permanent action that cannot be reversed!',
'delete_user' => 'Delete user account: :name',
'delete_user_confirm' => 'Are you sure you want to permanently remove :name\'s user account? They will be immediately logged out.',
'delete_user_warning' => 'This is a permanent action that cannot be reversed!',
'edit_album' => 'Edit photo album: :album_name',
'edit_album_intro' => 'Photo albums contain individual photographs together in the same way as a physical photo album or memory book.',
'edit_album_intro2' => 'Complete the form below to edit the properties of the album: :album_name.',
'edit_storage' => 'Edit storage location: :storage_name',
'edit_storage_intro' => 'Use the form below to update the details of the :storage_name storage location.',
'edit_user_intro' => 'You can use the form below to edit the above user account. Changes take effect immediately.',
'edit_user_title' => 'Edit user account: :name',
'is_uploading' => 'Uploading in progress...',
'manage_widget' => [
'panel_header' => 'Manage'
@ -87,5 +94,8 @@ return [
'upload_single_file_heading' => 'Upload photos individually',
'upload_single_file_text' => 'You can use the form below to upload individual files. To upload multiple files at once, hold down CTRL in the file browser.',
'upload_single_file_text2' => 'Your web server is configured to allow files up to :file_size. If you browser does not support HTML 5 (most modern browsers do), the combined size of all selected files must be less than :max_upload_size.',
'user_deletion_failed' => 'An error occurred while removing :name\'s user account: :error_message',
'user_deletion_successful' => 'The user account for :name was removed successfully.',
'user_pending' => 'Pending activation',
'users_title' => 'User accounts'
];

View File

@ -1,5 +1,6 @@
<?php
return [
'activate_user_label' => 'Manually activate this account',
'admin_user_label' => 'User is an administrator',
'album_source_label' => 'Storage location:',
'apply_action' => 'Apply',

View File

@ -8,8 +8,10 @@ return [
'create_user' => 'Create user',
'delete_album' => 'Delete album',
'delete_storage' => 'Delete storage location',
'delete_user' => 'Delete user',
'edit_album' => 'Edit album',
'edit_storage' => 'Edit storage location',
'edit_user' => 'Edit user',
'home' => 'Gallery',
'settings' => 'Settings',
'storage' => 'Storage',

View File

@ -0,0 +1,35 @@
@extends('themes.base.layout')
@section('title', trans('admin.delete_user', ['name' => $user->name]))
@section('breadcrumb')
<div class="breadcrumb">
<div class="container">
<ol class="breadcrumb">
<li><a href="{{ route('home') }}">@lang('navigation.breadcrumb.home')</a></li>
<li><a href="{{ route('admin') }}">@lang('navigation.breadcrumb.admin')</a></li>
<li><a href="{{ route('user.index') }}">@lang('navigation.breadcrumb.users')</a></li>
<li class="active">@lang('navigation.breadcrumb.delete_user')</li>
</ol>
</div>
</div>
@endsection
@section('content')
<div class="container">
<div class="row">
<div class="col-xs-12">
<h1>@yield('title')</h1>
<p>@lang('admin.delete_user_confirm', ['name' => $user->name])</p>
<div class="alert alert-danger">
@lang('admin.delete_user_warning')
</div>
<div class="form-actions">
{!! Form::open(['route' => ['user.destroy', $user->id], 'method' => 'DELETE']) !!}
<a href="{{ route('user.index') }}" class="btn btn-default">@lang('forms.cancel_action')</a>
{!! Form::submit(trans('forms.delete_action'), ['class' => 'btn btn-danger']) !!}
{!! Form::close() !!}
</div>
</div>
</div>
</div>
@endsection

View File

@ -0,0 +1,92 @@
@extends('themes.base.layout')
@section('title', trans('admin.edit_user_title', ['name' => $user->name]))
@section('breadcrumb')
<div class="breadcrumb">
<div class="container">
<ol class="breadcrumb">
<li><a href="{{ route('home') }}">@lang('navigation.breadcrumb.home')</a></li>
<li><a href="{{ route('admin') }}">@lang('navigation.breadcrumb.admin')</a></li>
<li><a href="{{ route('user.index') }}">@lang('navigation.breadcrumb.users')</a></li>
<li class="active">@lang('navigation.breadcrumb.edit_user')</li>
</ol>
</div>
</div>
@endsection
@section('content')
<div class="container">
<div class="row">
<div class="col-xs-12">
<h1>@yield('title')</h1>
<p>@lang('admin.edit_user_intro')</p>
<hr/>
@if (count($errors) > 0)
<div class="alert alert-danger">
<ul>
@foreach ($errors->all() as $form_error)
<li>{{ $form_error }}</li>
@endforeach
</ul>
</div>
@endif
{!! Form::model($user, ['route' => ['user.update', $user->id], 'method' => 'PUT']) !!}
<div class="row">
<div class="col-sm-6">
<div class="form-group">
{!! Form::label('name', trans('forms.name_label'), ['class' => 'control-label']) !!}
{!! Form::text('name', old('name'), ['class' => 'form-control']) !!}
</div>
</div>
<div class="col-sm-6">
<div class="form-group">
{!! Form::label('email', trans('forms.email_label'), ['class' => 'control-label']) !!}
{!! Form::text('email', old('email'), ['class' => 'form-control']) !!}
</div>
</div>
</div>
<div class="row">
<div class="col-sm-6">
<div class="form-group">
{!! Form::label('password', trans('forms.password_label'), ['class' => 'control-label']) !!}
{!! Form::password('password', ['class' => 'form-control']) !!}
</div>
</div>
<div class="col-sm-6">
<div class="form-group">
{!! Form::label('password_confirmation', trans('forms.password_confirm_label'), ['class' => 'control-label']) !!}
{!! Form::password('password_confirmation', ['class' => 'form-control']) !!}
</div>
</div>
</div>
<div class="checkbox">
<label>
<input type="checkbox" name="is_admin"@if ($user->is_admin) checked="checked"@endif>
<strong>@lang('forms.admin_user_label')</strong>
</label>
</div>
@if (!$user->is_activated)
<div class="checkbox">
<label>
<input type="checkbox" name="is_activated">
<strong>@lang('forms.activate_user_label')</strong>
</label>
</div>
@endif
<div class="form-actions">
<a href="{{ route('user.index') }}" class="btn btn-default">@lang('forms.cancel_action')</a>
{!! Form::submit(trans('forms.save_action'), ['class' => 'btn btn-success']) !!}
</div>
{!! Form::close() !!}
</div>
</div>
</div>
@endsection

View File

@ -23,6 +23,12 @@
<tr>
<td>
<span style="font-size: 1.3em;">{{ $user->name }}@if ($user->is_admin) <i class="fa fa-fw fa-cog"></i>@endif</span><br/>
<a href="mailto:{{ $user->email }}">{{ $user->email }}</a>
</td>
<td>
@if (!$user->is_activated)
<span style="font-style: italic; color: #888888;">@lang('admin.user_pending')</span>
@endif
</td>
<td class="text-right">
<a href="{{ route('user.edit', ['id' => $user->id]) }}" class="btn btn-default">@lang('forms.edit_action')</a>

View File

@ -32,7 +32,15 @@
@if (isset($error))
<div class="container">
<div class="alert alert-danger">
<strong><i class="fa fa-warning fa-fw"></i></strong> {{ $error }}
<strong><i class="fa fa-exclamation-circle fa-fw"></i></strong> {{ $error }}
</div>
</div>
@endif
@if (isset($warning))
<div class="container">
<div class="alert alert-warning">
<strong><i class="fa fa-warning fa-fw"></i></strong> {{ $warning }}
</div>
</div>
@endif