Files
librenms-librenms/app/Http/Controllers/UserController.php
eskyuu ce0734ff5d Added support for user timezones and user browser timezone by default (incomplete) (#13626)
* Added support for user timezones and user browser timezone byt default

* Formatting fixes

* Use the timezone for alert log display

also added validation for the timezone because it's being used in SQL.

* Formatting fixes

* Added return type

* Formatting"

* Update the latency graphs to use the user timezone

* Simplify the web routes config

* Update phpstan to ignore type error

* Fixed up the phpstan config

* Reverse phpstan change

* Re-apply phpstan override

* Remove the option to unset the session timezone

* Formatting fix

* Update outge and event logs to use session timezone

* Fix route for the timezone control

* Made the timezone more dynamic

* Fix a logic error that was stopping the timezone from being set automatically on login

* Prevent getPref from being called twice

* again prevent getPref double call

* getPref double call

* Fixed typo made during merge

* Fixed merge error in phpstan-baseline.neon

* Change spaces to tabs in phpstan-baseline.neon

* Update error count

---------

Co-authored-by: Tony Murray <murraytony@gmail.com>
2023-05-09 10:24:48 -05:00

285 lines
8.7 KiB
PHP

<?php
/**
* UserController.php
*
* -Description-
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* @link https://www.librenms.org
*
* @copyright 2018 Tony Murray
* @author Tony Murray <murraytony@gmail.com>
*/
namespace App\Http\Controllers;
use App\Http\Requests\StoreUserRequest;
use App\Http\Requests\UpdateUserRequest;
use App\Models\AuthLog;
use App\Models\Dashboard;
use App\Models\User;
use App\Models\UserPref;
use Auth;
use Flasher\Prime\FlasherInterface;
use Illuminate\Support\Str;
use LibreNMS\Authentication\LegacyAuth;
use LibreNMS\Config;
use URL;
class UserController extends Controller
{
public function __construct()
{
$this->middleware('deny-demo');
}
/**
* Display a listing of the resource.
*
* @return \Illuminate\View\View
*
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function index()
{
$this->authorize('manage', User::class);
return view('user.index', [
'users' => User::with('preferences')->orderBy('username')->get(),
'multiauth' => User::query()->distinct('auth_type')->count('auth_type') > 1,
]);
}
/**
* Show the form for creating a new resource.
*
* @return \Illuminate\View\View
*
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function create()
{
$this->authorize('create', User::class);
$tmp_user = new User;
$tmp_user->can_modify_passwd = (int) LegacyAuth::get()->canUpdatePasswords(); // default to true for new users
return view('user.create', [
'user' => $tmp_user,
'dashboard' => null,
'dashboards' => Dashboard::allAvailable($tmp_user)->get(),
'timezone' => 'default',
]);
}
/**
* Store a newly created resource in storage.
*
* @param StoreUserRequest $request
* @return \Illuminate\Http\RedirectResponse
*/
public function store(StoreUserRequest $request, FlasherInterface $flasher)
{
$user = $request->only(['username', 'realname', 'email', 'descr', 'level', 'can_modify_passwd']);
$user['auth_type'] = LegacyAuth::getType();
$user['can_modify_passwd'] = $request->get('can_modify_passwd'); // checkboxes are missing when unchecked
$user = User::create($user);
$user->setPassword($request->new_password);
$user->auth_id = (string) LegacyAuth::get()->getUserid($user->username) ?: $user->user_id;
$this->updateDashboard($user, $request->get('dashboard'));
$this->updateTimezone($user, $request->get('timezone'));
if ($user->save()) {
$flasher->addSuccess(__('User :username created', ['username' => $user->username]));
return redirect(route('users.index'));
}
$flasher->addError(__('Failed to create user'));
return redirect()->back();
}
/**
* Display the specified resource.
*
* @param User $user
* @return string
*
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function show(User $user)
{
$this->authorize('view', $user);
return $user->username;
}
/**
* Show the form for editing the specified resource.
*
* @param User $user
* @return \Illuminate\View\View
*
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function edit(User $user)
{
$this->authorize('update', $user);
$data = [
'user' => $user,
'dashboard' => UserPref::getPref($user, 'dashboard'),
'dashboards' => Dashboard::allAvailable($user)->get(),
'timezone' => UserPref::getPref($user, 'timezone') ?: 'default',
];
if (Config::get('twofactor')) {
$lockout_time = Config::get('twofactor_lock');
$twofactor = UserPref::getPref($user, 'twofactor');
$data['twofactor_enabled'] = isset($twofactor['key']);
// if enabled and 3 or more failures
$last_failure = isset($twofactor['last']) ? (time() - $twofactor['last']) : 0;
$data['twofactor_locked'] = isset($twofactor['fails']) && $twofactor['fails'] >= 3 && (! $lockout_time || $last_failure < $lockout_time);
}
return view('user.edit', $data);
}
/**
* Update the specified resource in storage.
*
* @param UpdateUserRequest $request
* @param User $user
* @return \Illuminate\Http\RedirectResponse
*/
public function update(UpdateUserRequest $request, User $user, FlasherInterface $flasher)
{
if ($request->get('new_password') && $user->canSetPassword($request->user())) {
$user->setPassword($request->new_password);
/** @var User $current_user */
$current_user = Auth::user();
Auth::setUser($user); // make sure new password is loaded, can only logout other sessions for the active user
Auth::logoutOtherDevices($request->new_password);
// when setting the password on another account, restore back to the user's account.
if ($current_user->user_id !== $user->user_id) {
Auth::setUser($current_user);
}
}
$user->fill($request->validated());
if ($request->has('dashboard') && $this->updateDashboard($user, $request->get('dashboard'))) {
$flasher->addSuccess(__('Updated dashboard for :username', ['username' => $user->username]));
}
if ($request->has('timezone') && $this->updateTimezone($user, $request->get('timezone'))) {
if ($request->get('timezone') != 'default') {
$flasher->addSuccess(__('Updated timezone for :username', ['username' => $user->username]));
} else {
$flasher->addSuccess(__('Cleared timezone for :username', ['username' => $user->username]));
}
}
if ($user->save()) {
$flasher->addSuccess(__('User :username updated', ['username' => $user->username]));
return redirect(route(Str::contains(URL::previous(), 'preferences') ? 'preferences.index' : 'users.index'));
}
$flasher->addError(__('Failed to update user :username', ['username' => $user->username]));
return redirect()->back();
}
/**
* Remove the specified resource from storage.
*
* @param User $user
* @return \Illuminate\Http\JsonResponse
*
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function destroy(User $user)
{
$this->authorize('delete', $user);
$user->delete();
return response()->json(__('User :username deleted.', ['username' => $user->username]));
}
/**
* @param User $user
* @param mixed $dashboard
* @return bool
*/
protected function updateDashboard(User $user, $dashboard)
{
if ($dashboard) {
$existing = UserPref::getPref($user, 'dashboard');
if ($dashboard != $existing) {
UserPref::setPref($user, 'dashboard', $dashboard);
return true;
}
}
return false;
}
/**
* @param User $user
* @param string $timezone
* @return bool
*/
protected function updateTimezone(User $user, $timezone)
{
$existing = UserPref::getPref($user, 'timezone');
if ($timezone != 'default') {
if (! in_array($timezone, timezone_identifiers_list())) {
return false;
}
if ($timezone != $existing) {
UserPref::setPref($user, 'timezone', $timezone);
return true;
}
} else {
if ($existing != '') {
UserPref::forgetPref($user, 'timezone');
return true;
}
}
return false;
}
public function authlog()
{
$this->authorize('manage', User::class);
return view('user.authlog', [
'authlog' => AuthLog::orderBy('datetime', 'DESC')->get(),
]);
}
}