AJenbo/agcms

View on GitHub
application/inc/Http/Controllers/Admin/UserController.php

Summary

Maintainability
B
5 hrs
Test Coverage
F
0%
<?php

namespace App\Http\Controllers\Admin;

use App\Exceptions\Handler as ExceptionHandler;
use App\Exceptions\InvalidInput;
use App\Http\Request;
use App\Models\Email;
use App\Models\User;
use App\Services\ConfigService;
use App\Services\DbService;
use App\Services\EmailService;
use App\Services\OrmService;
use App\Services\RenderService;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Response;
use Throwable;

class UserController extends AbstractAdminController
{
    /**
     * Index page for users.
     */
    public function index(Request $request): Response
    {
        $users = app(OrmService::class)->getByQuery(
            User::class,
            'SELECT * FROM `users` ORDER BY ' . ($request->get('order') ? 'lastlogin' : 'fullname')
        );

        $data = [
            'title'       => _('Users and Groups'),
            'currentUser' => $request->user(),
            'users'       => $users,
        ] + $this->basicPageData($request);

        return $this->render('admin/users', $data);
    }

    /**
     * Page for creating a new user.
     */
    public function newUser(Request $request): Response
    {
        $request->startSession();
        $session = $request->getSession();
        $message = $session->get('message', '');
        $session->remove('message');
        $session->save();

        return $this->render('admin/newuser', ['message' => $message]);
    }

    /**
     * Create a user.
     *
     * The new user must be verified by an admin.
     */
    public function create(Request $request): RedirectResponse
    {
        $fullname = $request->get('fullname');
        $name = $request->getRequestString('name') ?? '';
        $password = $request->getRequestString('password') ?? '';

        $message = _('Your account has been created. An administrator will evaluate it shortly.');

        try {
            if (!$fullname || !$name || !$password) {
                throw new InvalidInput(_('All fields must be filled.'));
            }
            if ($password !== $request->get('password2')) {
                throw new InvalidInput(_('The passwords do not match.'), Response::HTTP_FORBIDDEN);
            }

            $orm = app(OrmService::class);

            if ($orm->getOneByQuery(User::class, 'SELECT * FROM users WHERE name = ' . app(DbService::class)->quote($name))) {
                throw new InvalidInput(_('Username already taken.'));
            }
            $firstUser = !(bool)$orm->getOneByQuery(User::class, 'SELECT * FROM users WHERE access != 0');

            $user = new User([
                'full_name'     => $fullname,
                'nickname'      => $name,
                'password_hash' => '',
                'access_level'  => $firstUser ? User::ADMINISTRATOR : User::NO_ACCESS,
                'last_login'    => time(),
            ]);
            $user->setPassword($password)->save();

            $emailbody = app(RenderService::class)->render('admin/email/newuser', ['fullname' => $fullname]);

            $emailAddress = ConfigService::getDefaultEmail();
            $email = new Email([
                'subject'          => _('New user'),
                'body'             => $emailbody,
                'senderName'       => ConfigService::getString('site_name'),
                'senderAddress'    => $emailAddress,
                'recipientName'    => ConfigService::getString('site_name'),
                'recipientAddress' => $emailAddress,
            ]);

            try {
                app(EmailService::class)->send($email);
            } catch (Throwable $exception) {
                /** @var ExceptionHandler */
                $handler = app(ExceptionHandler::class);
                $handler->report($exception);
                $email->save();
            }
        } catch (InvalidInput $exception) {
            $message = $exception->getMessage();
        }

        $request->startSession();
        $session = $request->getSession();
        $session->set('message', $message);
        $session->save();

        return redirect('/admin/users/new/', Response::HTTP_SEE_OTHER);
    }

    public function editUser(Request $request, int $id): Response
    {
        $user = app(OrmService::class)->getOne(User::class, $id);
        if (!$user) {
            throw new InvalidInput(_('User not found.'), Response::HTTP_NOT_FOUND);
        }

        $data = [
            'title'        => _('Edit') . ' ' . $user->getFullName(),
            'currentUser'  => $request->user(),
            'user'         => $user,
            'accessLevels' => [
                User::NO_ACCESS     => _('No access'),
                User::ADMINISTRATOR => _('Administrator'),
                User::MANAGER       => _('Manager'),
                User::CLERK         => _('Clerk'),
            ],
        ] + $this->basicPageData($request);

        return $this->render('admin/user', $data);
    }

    public function update(Request $request, int $id): JsonResponse
    {
        $user = $request->user();
        if (!$user || (!$user->hasAccess(User::ADMINISTRATOR) && $user->getId() !== $id)) {
            throw new InvalidInput(_('You do not have permission to edit users.'), Response::HTTP_FORBIDDEN);
        }

        // Validate access lavel update
        if ($user->getId() === $id
            && $request->request->getInt('access') !== $user->getAccessLevel()
        ) {
            throw new InvalidInput(_('You can\'t change your own access level.'), Response::HTTP_FORBIDDEN);
        }

        $user = app(OrmService::class)->getOne(User::class, $id);
        if (!$user) {
            throw new InvalidInput(_('User not found.'), Response::HTTP_NOT_FOUND);
        }

        // Validate password update
        $newPassword = $request->getRequestString('password_new');
        if ($newPassword) {
            if (!$user->hasAccess(User::ADMINISTRATOR) && $user->getId() !== $id) {
                throw new InvalidInput(
                    _('You do not have the required access level to change the password for this user.'),
                    Response::HTTP_FORBIDDEN
                );
            }

            $password = $request->getRequestString('password');
            if (!$password || ($user->getId() === $id && !$user->validatePassword($password))) {
                throw new InvalidInput(_('Incorrect password.'), Response::HTTP_FORBIDDEN);
            }

            $user->setPassword($newPassword);
        }

        if ($request->request->has('access')) {
            $user->setAccessLevel($request->request->getInt('access'));
        }

        if ($request->request->has('fullname')) {
            $user->setFullName($request->getRequestString('fullname') ?? '');
        }

        $user->save();

        return new JsonResponse([]);
    }

    public function delete(Request $request, int $id): JsonResponse
    {
        $user = $request->user();
        if (!$user || !$user->hasAccess(User::ADMINISTRATOR)) {
            throw new InvalidInput(_('You do not have permission to edit users.'), Response::HTTP_FORBIDDEN);
        }
        if ($user->getId() === $id) {
            throw new InvalidInput(_('You can\'t delete yourself.'), Response::HTTP_FORBIDDEN);
        }

        $user = app(OrmService::class)->getOne(User::class, $id);
        if ($user) {
            $user->delete();
        }

        return new JsonResponse([]);
    }
}