mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-09-20 19:35:16 +00:00
Extended the user admin.
This commit is contained in:
@@ -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'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@@ -25,6 +25,7 @@ use FireflyIII\Models\RuleGroup;
|
||||
use FireflyIII\Models\Tag;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\User;
|
||||
|
||||
/**
|
||||
* 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(
|
||||
'admin.users.domains', function (BreadCrumbGenerator $breadcrumbs) {
|
||||
$breadcrumbs->parent('admin.index');
|
||||
|
@@ -14,9 +14,11 @@ declare(strict_types = 1);
|
||||
namespace FireflyIII\Repositories\User;
|
||||
|
||||
|
||||
use FireflyIII\Models\BudgetLimit;
|
||||
use FireflyIII\Models\Role;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Support\Collection;
|
||||
use Preferences;
|
||||
|
||||
/**
|
||||
* Class UserRepository
|
||||
@@ -56,4 +58,59 @@ class UserRepository implements UserRepositoryInterface
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@@ -31,6 +31,15 @@ interface UserRepositoryInterface
|
||||
*/
|
||||
public function all(): Collection;
|
||||
|
||||
/**
|
||||
* Return basic user information.
|
||||
*
|
||||
* @param User $user
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getUserData(User $user): array;
|
||||
|
||||
/**
|
||||
* Gives a user a role.
|
||||
*
|
||||
|
@@ -280,7 +280,7 @@ return [
|
||||
'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_do_show_deposits' => 'Yes, show them',
|
||||
|
||||
'successful_count' => 'of which :count successful',
|
||||
'transaction_page_size_title' => 'Page size',
|
||||
'transaction_page_size_help' => 'Any list of transactions shows at most this many transactions',
|
||||
'transaction_page_size_label' => 'Page size',
|
||||
@@ -735,7 +735,15 @@ return [
|
||||
'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).',
|
||||
'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>.',
|
||||
'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:
|
||||
'transaction_meta_data' => 'Transaction meta-data',
|
||||
|
@@ -25,6 +25,7 @@ return [
|
||||
'matchedOn' => 'Matched on',
|
||||
'matchesOn' => 'Matched on',
|
||||
'account_type' => 'Account type',
|
||||
'created_at' => 'Created at',
|
||||
'new_balance' => 'New balance',
|
||||
'account' => 'Account',
|
||||
'matchingAmount' => 'Amount',
|
||||
@@ -71,4 +72,15 @@ return [
|
||||
'blocked_code' => 'Block code',
|
||||
'domain' => 'Domain',
|
||||
'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',
|
||||
];
|
||||
|
@@ -35,7 +35,8 @@
|
||||
</div>
|
||||
</td>
|
||||
<td>#{{ user.id }}</td>
|
||||
<td>{{ user.email }}</td>
|
||||
<td>
|
||||
<a href="{{ route('admin.users.show',user.id) }}">{{ user.email }}</a></td>
|
||||
<td>
|
||||
{{ user.created_at.formatLocalized(monthAndDayFormat) }}
|
||||
{{ user.created_at.format('H:i') }}
|
||||
|
151
resources/views/admin/users/show.twig
Normal file
151
resources/views/admin/users/show.twig
Normal 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 %}
|
@@ -435,6 +435,7 @@ Route::group(
|
||||
// user manager
|
||||
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/show/{user}', ['uses' => 'Admin\UserController@show', 'as' => 'admin.users.show']);
|
||||
|
||||
// user domains:
|
||||
Route::get('/admin/domains', ['uses' => 'Admin\DomainController@domains', 'as' => 'admin.users.domains']);
|
||||
|
Reference in New Issue
Block a user