* @copyright 2020 Copyright XEHub Corp. * @license http://www.gnu.org/licenses/lgpl-3.0-standalone.html LGPL * @link https://xpressengine.io */ namespace App\Http\Controllers\User\Settings; use App\Http\Controllers\Controller; use Exception; use Illuminate\Database\Eloquent\Builder; use Symfony\Component\HttpKernel\Exception\HttpException; use XeDB; use XePresenter; use Xpressengine\Http\Request; use Xpressengine\Support\Exceptions\InvalidArgumentHttpException; use Xpressengine\User\Exceptions\EmailAlreadyExistsException; use Xpressengine\User\Exceptions\EmailNotFoundException; use Xpressengine\User\Models\User; use Xpressengine\User\Rating; use Xpressengine\User\Repositories\UserRepository; use Xpressengine\User\UserException; use Xpressengine\User\UserHandler; use Xpressengine\User\UserInterface; /** * Class UserController * * @category Controllers * @package App\Http\Controllers\User\Settings * @author XE Developers * @copyright 2020 Copyright XEHub Corp. * @license http://www.gnu.org/licenses/lgpl-3.0-standalone.html LGPL * @link https://xpressengine.io */ class UserController extends Controller { /** * @var UserHandler */ protected $handler; /** * UserController constructor. * * @param UserHandler $handler user handler */ public function __construct(UserHandler $handler) { $this->handler = $handler; } /** * Show user list * * @param Request $request request * @return \Xpressengine\Presenter\Presentable */ public function index(Request $request) { $query = $this->handler->users()->query(); $allUserCount = $query->count(); if ($startDate = $request->get('startDate')) { $query = $query->where('created_at', '>=', $startDate . ' 00:00:00'); } if ($endDate = $request->get('endDate')) { $query = $query->where('created_at', '<=', $endDate . ' 23:59:59'); } // resolve group if ($group = $request->get('group')) { $query = $query->whereHas( 'groups', function (Builder $q) use ($group) { $q->where('group_id', $group); } ); } // resolve status if ($status = $request->get('status')) { $query = $query->where('status', $status); } // resolve rating if ($rating = $request->get('rating')) { $query = $query->where('rating', $rating); } // resolve search keyword // keyfield가 지정되지 않을 경우 email, display_name, login_id를 대상으로 검색함 $field = $request->get('keyfield') ?: 'email,display_name,login_id'; if ($keyword = trim($request->get('keyword'))) { $query = $query->where( function (Builder $q) use ($field, $keyword) { foreach (explode(',', $field) as $f) { $q->orWhere($f, 'like', '%'.$keyword.'%'); } } ); } $users = $query->orderBy('created_at', 'desc')->paginate()->appends(request()->query()); // get all groups $groups = $this->handler->groups()->all(); // get all ratings $ratings = Rating::getUsableAll(); $ratingNames = [ Rating::USER => xe_trans('xe::userRatingNormal'), Rating::MANAGER => xe_trans('xe::userRatingManager'), Rating::SUPER => xe_trans('xe::userRatingAdministrator'), ]; foreach ($ratings as $key => $rating) { $ratings[$key] = [ 'value' => $rating, 'text' => $ratingNames[$rating], ]; } $selectedGroup = null; if ($group !== null) { $selectedGroup = $this->handler->groups()->find($group); } $config = app('xe.config')->get('user.register'); return XePresenter::make( 'user.settings.user.index', compact('users', 'groups', 'selectedGroup', 'allUserCount', 'ratings', 'config') ); } /** * Show user creation page. * * @return \Xpressengine\Presenter\Presentable */ public function create() { $ratings = Rating::getUsableAll(); $ratingNames = [ Rating::USER => xe_trans('xe::userRatingNormal'), Rating::MANAGER => xe_trans('xe::userRatingManager'), Rating::SUPER => xe_trans('xe::userRatingAdministrator'), ]; foreach ($ratings as $key => $rating) { $ratings[$key] = [ 'value' => $rating, 'text' => $ratingNames[$rating], ]; } $groupList = $this->handler->groups()->all(); $groups = $this->getGroupInfo($groupList); $status = $this->getUserStatus(); // dynamic field $dynamicField = app('xe.dynamicField'); $fieldTypes = $dynamicField->gets('user'); return XePresenter::make('user.settings.user.create', compact('ratings', 'groups', 'status', 'fieldTypes')); } /** * Store user. * * @param Request $request request * @return \Illuminate\Http\RedirectResponse * @throws Exception */ public function store(Request $request) { $rules = [ 'email' => 'email|required', 'login_id' => 'required|login_id', 'password' => 'required|password', ]; if (app('xe.config')->getVal('user.register.use_display_name') === true) { $rules['display_name'] = 'required'; } $this->validate($request, $rules); $userData = $request->except('_token'); $userData['emailConfirmed'] = 1; XeDB::beginTransaction(); try { $this->handler->create($userData); } catch (\Exception $e) { XeDB::rollback(); throw $e; } XeDB::commit(); return redirect()->route('settings.user.index')->with( 'alert', ['type' => 'success', 'message' => xe_trans('xe::saved')] ); } /** * Show user editing page. * * @param string $id identifier * @return \Xpressengine\Presenter\Presentable */ public function edit($id) { $user = $this->handler->users()->with('groups', 'emails', 'accounts')->find($id); if ($user === null) { $e = new InvalidArgumentHttpException(); $e->setMessage(xe_trans('xe::userNotFound')); throw $e; } $ratings = Rating::getUsableAll(); $ratingNames = [ Rating::USER => xe_trans('xe::userRatingNormal'), Rating::MANAGER => xe_trans('xe::userRatingManager'), Rating::SUPER => xe_trans('xe::userRatingAdministrator'), ]; foreach ($ratings as $key => $rating) { $ratings[$key] = [ 'value' => $rating, 'text' => $ratingNames[$rating], ]; if ($rating === $user->rating) { $ratings[$key]['selected'] = 'selected'; } } $groupList = $this->handler->groups()->all(); $groups = $this->getGroupInfo($groupList); foreach ($user->groups as $group) { $groups[$group->id]['checked'] = 'checked'; } $status = $this->getUserStatus(); $status[$user->status]['selected'] = 'selected'; // profileImage config $profileImgSize = config('xe.user.profileImage.size'); // dynamic field $dynamicField = app('xe.dynamicField'); $fieldTypes = $dynamicField->gets('user'); return XePresenter::make( 'user.settings.user.edit', compact( 'user', 'ratings', 'groups', 'status', 'fieldTypes', 'profileImgSize' ) ); } /** * Update user. * * @param Request $request request * @param string $id user id * @return \Illuminate\Http\RedirectResponse * @throws Exception */ public function update(Request $request, $id) { /** @var UserInterface $user */ $user = $this->handler->users()->with('groups', 'emails', 'accounts')->find($id); if ($user === null) { $e = new InvalidArgumentHttpException(); $e->setMessage(xe_trans('xe::userNotFound')); throw $e; } $rules = [ 'email' => 'email', 'login_id' => 'required|login_id', 'rating' => 'required', 'status' => 'required', ]; if (app('xe.config')->getVal('user.register.use_display_name') === true) { $rules['display_name'] = 'required'; } $this->validate($request, $rules); if ($user->isAdmin() && ($request->get('status') === User::STATUS_DENIED || $request->get('rating') !== Rating::SUPER) ) { $cnt = $this->handler->users() ->where('rating', Rating::SUPER) ->where('status', User::STATUS_ACTIVATED) ->count(); if ($cnt === 1) { throw new HttpException(422, xe_trans('xe::msgUnableToChangeStatusForSuperUser')); } } $userData = $request->except('_token'); if (array_get($userData, 'profile_img_file') === '__delete_file__') { $userData['profile_img_file'] = false; } $userData['group_id'] = $request->get('group_id') ?: []; XeDB::beginTransaction(); try { $this->handler->update($user, $userData); } catch (UserException $e) { XeDB::rollback(); throw new HttpException('400', $e->getMessage()); } catch (\Exception $e) { XeDB::rollback(); throw $e; } XeDB::commit(); return redirect()->back()->with('alert', ['type' => 'success', 'message' => xe_trans('xe::saved')]); } /** * get user status list * * @return array */ protected function getUserStatus() { return [ User::STATUS_ACTIVATED => ['value' => User::STATUS_ACTIVATED, 'text' => xe_trans('xe::permitted')], User::STATUS_DENIED => ['value' => User::STATUS_DENIED, 'text' => xe_trans('xe::rejected')], User::STATUS_PENDING_ADMIN => [ 'value' => User::STATUS_PENDING_ADMIN, 'text' => xe_trans('xe::pending_admin') ], User::STATUS_PENDING_EMAIL => [ 'value' => User::STATUS_PENDING_EMAIL, 'text' => xe_trans('xe::pending_email') ] ]; } /** * Response user's email list. * * @return \Xpressengine\Presenter\Presentable */ public function getMailList(Request $request) { $this->validate($request, ['userId' => 'required']); $id = $request->get('userId'); $mails = $this->handler->emails()->where(['user_id' => $id])->get(); return XePresenter::makeApi(['mails' => $mails]); } /** * Add email. * * @param Request $request request * @return \Xpressengine\Presenter\Presentable * @throws Exception */ public function postAddMail(Request $request) { $this->validate($request, [ 'userId' => 'required', 'address' => 'required|email' ]); $userId = $request->get('userId'); $address = $request->get('address'); try { $this->handler->validateEmail($address); } catch (EmailAlreadyExistsException $e) { throw new HttpException(400, xe_trans('xe::emailAlreadyExists'), $e); } $user = $this->handler->users()->find($userId); XeDB::beginTransaction(); try { $data = [ 'user_id' => $user->id, 'address' => $address, ]; $email = $this->handler->createEmail($user, $data); } catch (Exception $e) { XeDB::rollBack(); throw $e; } XeDB::commit(); return XePresenter::makeApi(['mail' => $email]); } /** * Confirm email * * @param Request $request request * @return \Xpressengine\Presenter\Presentable * @throws Exception */ public function postConfirmMail(Request $request) { $pendingEmail = $this->handler->pendingEmails()->find($request->get('id')); if ($pendingEmail === null) { $e = new InvalidArgumentHttpException(); $e->setMessage(xe_trans('xe::EmailNotExistOrAlreadyConfirmed')); throw $e; } $user = $pendingEmail->user; $address = $pendingEmail->address; XeDB::beginTransaction(); try { // create email $email = $this->handler->createEmail($user, compact('address')); // remove pending email $this->handler->deleteEmail($pendingEmail); } catch (Exception $e) { XeDB::rollBack(); throw $e; } XeDB::commit(); return XePresenter::makeApi(['mail' => $email]); } /** * Delete a mail. * * @param Request $request request * @return \Xpressengine\Presenter\Presentable * @throws Exception */ public function postDeleteMail(Request $request) { $this->validate($request, [ 'userId' => 'required', 'address' => 'required' ]); $address = $request->get('address'); $mail = $this->handler->emails()->findByAddress($address); if ($mail === null) { throw new EmailNotFoundException(); } XeDB::beginTransaction(); try { $this->handler->deleteEmail($mail); } catch (Exception $e) { XeDB::rollBack(); throw $e; } XeDB::commit(); return XePresenter::makeApi(['type' => 'success', 'address' => $address]); } /** * Show confirm for delete a user. * * @param Request $request request * @return \Xpressengine\Presenter\Presentable */ public function deletePage(Request $request) { $userIds = $request->get('userIds'); $userIds = explode(',', $userIds); $users = $this->handler->users()->whereIn('id', $userIds)->where('rating', '<>', Rating::SUPER)->get(); return api_render('user.settings.user.delete', compact('users')); } /** * Delete a user. * * @param Request $request request * @return \Illuminate\Http\RedirectResponse * @throws Exception */ public function destroy(Request $request) { $userIds = $request->get('userId', []); XeDB::beginTransaction(); try { $this->handler->leave($userIds); } catch (Exception $e) { XeDB::rollBack(); throw $e; } XeDB::commit(); return redirect()->back()->with('alert', ['type' => 'success', 'message' => xe_trans('xe::deleted')]); } /** * Search user. * * @param string|null $keyword keyword * @return \Xpressengine\Presenter\Presentable */ public function search($keyword = null) { /** @var UserRepository $users */ $users = $this->handler->users(); if ($keyword === null) { return XePresenter::makeApi([]); } $matchedUserList = $users->query()->where('display_name', 'like', '%'.$keyword.'%') ->paginate(null, ['id', 'display_name', 'email'])->items(); return XePresenter::makeApi($matchedUserList); } /** * Get group information * * @param \Xpressengine\User\Models\UserGroup[] $groupList groups * @return array */ protected function getGroupInfo($groupList) { $groups = []; foreach ($groupList as $key => $group) { $groups[$group->id] = [ 'value' => $group->id, 'text' => $group->name, ]; } return $groups; } }