Extended the user admin.

This commit is contained in:
James Cole
2016-10-15 07:11:53 +02:00
parent 6e4f2c0c8a
commit ac968dd6cd
9 changed files with 763 additions and 480 deletions

View File

@@ -78,5 +78,41 @@ class UserController extends Controller
} }
/**
* @param UserRepositoryInterface $repository
* @param User $user
*
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
*/
public function show(UserRepositoryInterface $repository, User $user)
{
$title = strval(trans('firefly.administration'));
$mainTitleIcon = 'fa-hand-spock-o';
$subTitle = strval(trans('firefly.single_user_administration', ['email' => $user->email]));
$subTitleIcon = 'fa-user';
$defaultIp = '0.0.0.0';
$registration = Preferences::getForUser($user, 'registration_ip_address', $defaultIp)->data;
$confirmation = Preferences::getForUser($user, 'confirmation_ip_address', $defaultIp)->data;
$registrationHost = '';
$confirmationHost = '';
if ($registration != $defaultIp) {
$registrationHost = gethostbyaddr($registration);
}
if ($confirmation != $defaultIp) {
$confirmationHost = gethostbyaddr($confirmation);
}
$information = $repository->getUserData($user);
return view(
'admin.users.show',
compact(
'title', 'mainTitleIcon', 'subTitle', 'subTitleIcon', 'information',
'user', 'registration', 'confirmation', 'registrationHost', 'confirmationHost'
)
);
}
} }

View File

@@ -25,6 +25,7 @@ use FireflyIII\Models\RuleGroup;
use FireflyIII\Models\Tag; use FireflyIII\Models\Tag;
use FireflyIII\Models\TransactionCurrency; use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Models\TransactionJournal; use FireflyIII\Models\TransactionJournal;
use FireflyIII\User;
/** /**
* HOME * HOME
@@ -115,6 +116,13 @@ Breadcrumbs::register(
} }
); );
Breadcrumbs::register(
'admin.users.show', function (BreadCrumbGenerator $breadcrumbs, User $user) {
$breadcrumbs->parent('admin.users');
$breadcrumbs->push(trans('firefly.single_user_administration', ['email' => $user->email]), route('admin.users.show', $user->id));
}
);
Breadcrumbs::register( Breadcrumbs::register(
'admin.users.domains', function (BreadCrumbGenerator $breadcrumbs) { 'admin.users.domains', function (BreadCrumbGenerator $breadcrumbs) {
$breadcrumbs->parent('admin.index'); $breadcrumbs->parent('admin.index');

View File

@@ -14,9 +14,11 @@ declare(strict_types = 1);
namespace FireflyIII\Repositories\User; namespace FireflyIII\Repositories\User;
use FireflyIII\Models\BudgetLimit;
use FireflyIII\Models\Role; use FireflyIII\Models\Role;
use FireflyIII\User; use FireflyIII\User;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Preferences;
/** /**
* Class UserRepository * Class UserRepository
@@ -56,4 +58,59 @@ class UserRepository implements UserRepositoryInterface
{ {
return $this->all()->count(); return $this->all()->count();
} }
/**
* Return basic user information.
*
* @param User $user
*
* @return array
*/
public function getUserData(User $user): array
{
$return = [];
// two factor:
$is2faEnabled = Preferences::getForUser($user, 'twoFactorAuthEnabled', false)->data;
$has2faSecret = !is_null(Preferences::getForUser($user, 'twoFactorAuthSecret'));
$return['has_2fa'] = false;
if ($is2faEnabled && $has2faSecret) {
$return['has_2fa'] = true;
}
// is user activated?
$confirmAccount = env('MUST_CONFIRM_ACCOUNT', false);
$isConfirmed = Preferences::getForUser($user, 'user_confirmed', false)->data;
$return['is_activated'] = true;
if ($isConfirmed === false && $confirmAccount === true) {
$return['is_activated'] = false;
}
$return['is_admin'] = $user->hasRole('owner');
$return['blocked'] = intval($user->blocked) === 1;
$return['blocked_code'] = $user->blocked_code;
$return['accounts'] = $user->accounts()->count();
$return['journals'] = $user->transactionJournals()->count();
$return['transactions'] = $user->transactions()->count();
$return['attachments'] = $user->attachments()->count();
$return['attachments_size'] = $user->attachments()->sum('size');
$return['bills'] = $user->bills()->count();
$return['categories'] = $user->categories()->count();
$return['budgets'] = $user->budgets()->count();
$return['budgets_with_limits'] = BudgetLimit
::distinct()
->leftJoin('budgets', 'budgets.id', '=', 'budget_limits.budget_id')
->where('amount', '>', 0)
->whereNull('budgets.deleted_at')
->where('budgets.user_id', $user->id)->get(['budget_limits.budget_id'])->count();
$return['export_jobs'] = $user->exportJobs()->count();
$return['export_jobs_success'] = $user->exportJobs()->where('status', 'export_downloaded')->count();
$return['import_jobs'] = $user->exportJobs()->count();
$return['import_jobs_success'] = $user->exportJobs()->where('status', 'import_complete')->count();
$return['rule_groups'] = $user->ruleGroups()->count();
$return['rules'] = $user->rules()->count();
$return['tags'] = $user->tags()->count();
return $return;
}
} }

View File

@@ -31,6 +31,15 @@ interface UserRepositoryInterface
*/ */
public function all(): Collection; public function all(): Collection;
/**
* Return basic user information.
*
* @param User $user
*
* @return array
*/
public function getUserData(User $user): array;
/** /**
* Gives a user a role. * Gives a user a role.
* *

View File

@@ -280,7 +280,7 @@ return [
'pref_home_show_deposits' => 'Show deposits on the home screen', 'pref_home_show_deposits' => 'Show deposits on the home screen',
'pref_home_show_deposits_info' => 'The home screen already shows your expense accounts. Should it also show your revenue accounts?', 'pref_home_show_deposits_info' => 'The home screen already shows your expense accounts. Should it also show your revenue accounts?',
'pref_home_do_show_deposits' => 'Yes, show them', 'pref_home_do_show_deposits' => 'Yes, show them',
'successful_count' => 'of which :count successful',
'transaction_page_size_title' => 'Page size', 'transaction_page_size_title' => 'Page size',
'transaction_page_size_help' => 'Any list of transactions shows at most this many transactions', 'transaction_page_size_help' => 'Any list of transactions shows at most this many transactions',
'transaction_page_size_label' => 'Page size', 'transaction_page_size_label' => 'Page size',
@@ -735,7 +735,15 @@ return [
'setting_single_user_mode' => 'Single user mode', 'setting_single_user_mode' => 'Single user mode',
'setting_single_user_mode_explain' => 'By default, Firefly III only accepts one (1) registration: you. This is a security measure, preventing others from using your instance unless you allow them to. Future registrations are blocked. When you uncheck this box, others can use your instance as wel, assuming they can reach it (when it is connected to the internet).', 'setting_single_user_mode_explain' => 'By default, Firefly III only accepts one (1) registration: you. This is a security measure, preventing others from using your instance unless you allow them to. Future registrations are blocked. When you uncheck this box, others can use your instance as wel, assuming they can reach it (when it is connected to the internet).',
'store_configuration' => 'Store configuration', 'store_configuration' => 'Store configuration',
'single_user_administration' => 'User administration for :email',
'hidden_fields_preferences' => 'Not all fields are visible right now. You must enable them in your <a href=":link">settings</a>.', 'hidden_fields_preferences' => 'Not all fields are visible right now. You must enable them in your <a href=":link">settings</a>.',
'user_data_information' => 'User data',
'user_information' => 'User information',
'total_size' => 'total size',
'budget_or_budgets' => 'budget(s)',
'budgets_with_limits' => 'budget(s) with configured amount',
'rule_or_rules' => 'rule(s)',
'rulegroup_or_groups' => 'rule group(s)',
// split a transaction: // split a transaction:
'transaction_meta_data' => 'Transaction meta-data', 'transaction_meta_data' => 'Transaction meta-data',

View File

@@ -25,6 +25,7 @@ return [
'matchedOn' => 'Matched on', 'matchedOn' => 'Matched on',
'matchesOn' => 'Matched on', 'matchesOn' => 'Matched on',
'account_type' => 'Account type', 'account_type' => 'Account type',
'created_at' => 'Created at',
'new_balance' => 'New balance', 'new_balance' => 'New balance',
'account' => 'Account', 'account' => 'Account',
'matchingAmount' => 'Amount', 'matchingAmount' => 'Amount',
@@ -71,4 +72,15 @@ return [
'blocked_code' => 'Block code', 'blocked_code' => 'Block code',
'domain' => 'Domain', 'domain' => 'Domain',
'registration_attempts' => 'Registration attempts', 'registration_attempts' => 'Registration attempts',
'accounts_count' => 'Number of accounts',
'journals_count' => 'Number of journals',
'attachments_count' => 'Number of attachments',
'bills_count' => 'Number of bills',
'categories_count' => 'Number of categories',
'export_jobs_count' => 'Number of export jobs',
'import_jobs_count' => 'Number of import jobs',
'budget_count' => 'Number of budgets',
'rule_and_groups_count' => 'Number of rules and rule groups',
'tags_count' => 'Number of tags',
]; ];

View File

@@ -35,7 +35,8 @@
</div> </div>
</td> </td>
<td>#{{ user.id }}</td> <td>#{{ user.id }}</td>
<td>{{ user.email }}</td> <td>
<a href="{{ route('admin.users.show',user.id) }}">{{ user.email }}</a></td>
<td> <td>
{{ user.created_at.formatLocalized(monthAndDayFormat) }} {{ user.created_at.formatLocalized(monthAndDayFormat) }}
{{ user.created_at.format('H:i') }} {{ user.created_at.format('H:i') }}

View File

@@ -0,0 +1,151 @@
{% extends "./layout/default.twig" %}
{% block breadcrumbs %}
{{ Breadcrumbs.renderIfExists(Route.getCurrentRoute.getName, user) }}
{% endblock %}
{% block content %}
<div class="row">
<div class="col-lg-6 col-md-6 col-sm-12 col-xs-12">
<div class="box box-primary">
<div class="box-header with-border">
<h3 class="box-title">{{ 'user_information'|_ }}</h3>
</div>
<div class="box-body table-responsive">
<table class="table table-striped table-bordered">
<tbody>
<tr>
<td>{{ trans('list.id') }}</td>
<td>#{{ user.id }}</td>
</tr>
<tr>
<td>{{ trans('list.email') }}</td>
<td><a href="mailto:{{ user.email }}">{{ user.email }}</a>
<td>
</tr>
<tr>
<td>{{ trans('list.created_at') }}</td>
<td>
{{ user.created_at.formatLocalized(monthAndDayFormat) }}
{{ user.created_at.format('H:i') }}</td>
</tr>
<tr>
<td>{{ trans('list.registered_from') }}</td>
<td>{{ registration }} ({{ registrationHost }})</td>
</tr>
<tr>
<td>{{ trans('list.confirmed_from') }}</td>
<td>{{ confirmation }} ({{ confirmationHost }})</td>
</tr>
<tr>
<td>{{ trans('list.is_admin') }}</td>
<td>
{% if information.is_admin %}
<small class="text-success"><i class="fa fa-fw fa-check"></i></small> Yes
{% else %}
<small class="text-danger"><i class="fa fa-fw fa-times"></i></small> No
{% endif %}
</td>
</tr>
<tr>
<td>{{ trans('list.has_two_factor') }}</td>
<td>
{% if information.has_2fa %}
<small class="text-success"><i class="fa fa-fw fa-check"></i></small> Yes
{% else %}
<small class="text-danger"><i class="fa fa-fw fa-times"></i></small> No
{% endif %}
</td>
</tr>
<tr>
<td>{{ trans('list.is_activated') }}</td>
<td>
{% if information.activated %}
<small class="text-success"><i class="fa fa-fw fa-check"></i></small> Yes
{% else %}
<small class="text-danger"><i class="fa fa-fw fa-times"></i></small> No
{% endif %}
</td>
</tr>
<tr>
<td>{{ trans('list.is_blocked') }}</td>
<td>
{% if information.blocked == 1 %}
<small class="text-danger"><i class="fa fa-fw fa-check" title="{{ 'yes'|_ }}"></i></small> Yes:
{% if information.blocked_code == "" %}
<em>~</em>
{% else %}
{{ information.blocked_code }}
{% endif %}
{% else %}
<small class="text-success"><i class="fa fa-fw fa-times" title="{{ 'no'|_ }}"></i></small> No
{% endif %}
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div class="col-lg-6 col-md-6 col-sm-12 col-xs-12">
<div class="box box-primary">
<div class="box-header with-border">
<h3 class="box-title">{{ 'user_data_information'|_ }}</h3>
</div>
<div class="box-body table-responsive">
<table class="table table-striped table-bordered">
<tr>
<td>{{ trans('list.accounts_count') }}</td>
<td>{{ information.accounts }}</td>
</tr>
<tr>
<td>{{ trans('list.journals_count') }}</td>
<td>{{ information.journals }} ({{ information.transactions }} {{ trans('firefly.transactions') }})</td>
</tr>
<tr>
<td>{{ trans('list.attachments_count') }}</td>
<td>{{ information.attachments }} ({{ trans('firefly.total_size') }}: {{ information.attachments_size|filesize }})</td>
</tr>
<tr>
<td>{{ trans('list.bills_count') }}</td>
<td>{{ information.bills }}</td>
</tr>
<tr>
<td>{{ trans('list.categories_count') }}</td>
<td>{{ information.categories }}</td>
</tr>
<tr>
<td>{{ trans('list.export_jobs_count') }}</td>
<td>{{ information.export_jobs }}, {{ trans('firefly.successful_count', {count: information.export_jobs_success}) }}
<!-- of which x successful --></td>
</tr>
<tr>
<td>{{ trans('list.import_jobs_count') }}</td>
<td>{{ information.import_jobs }}, {{ trans('firefly.successful_count', {count: information.import_jobs_success}) }}
<!-- of which x successful --></td>
</tr>
<tr>
<td>{{ trans('list.budget_count') }}</td>
<td>{{ information.budgets }} {{ trans('firefly.budget_or_budgets') }},
{{ information.budgets_with_limits }} {{ trans('firefly.budgets_with_limits') }}</td>
</tr>
<tr>
<td>{{ trans('list.rule_and_groups_count') }}</td>
<td>
{{ information.rules }} {{ 'rule_or_rules'|_ }} {{ 'in'|_ }} {{ information.rule_groups }}
{{ 'rulegroup_or_groups'|_ }}
</td>
</tr>
<tr>
<td>{{ trans('list.tags_count') }}</td>
<td>{{ information.tags }} tags</td>
</tr>
</table>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@@ -435,6 +435,7 @@ Route::group(
// user manager // user manager
Route::get('/admin/users', ['uses' => 'Admin\UserController@index', 'as' => 'admin.users']); Route::get('/admin/users', ['uses' => 'Admin\UserController@index', 'as' => 'admin.users']);
Route::get('/admin/users/edit/{user}', ['uses' => 'Admin\UserController@edit', 'as' => 'admin.users.edit']); Route::get('/admin/users/edit/{user}', ['uses' => 'Admin\UserController@edit', 'as' => 'admin.users.edit']);
Route::get('/admin/users/show/{user}', ['uses' => 'Admin\UserController@show', 'as' => 'admin.users.show']);
// user domains: // user domains:
Route::get('/admin/domains', ['uses' => 'Admin\DomainController@domains', 'as' => 'admin.users.domains']); Route::get('/admin/domains', ['uses' => 'Admin\DomainController@domains', 'as' => 'admin.users.domains']);