Skip to content

Instantly share code, notes, and snippets.

@baytalov
Last active June 28, 2017 08:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save baytalov/521e7b56c60dcd3da199d028b9b029cc to your computer and use it in GitHub Desktop.
Save baytalov/521e7b56c60dcd3da199d028b9b029cc to your computer and use it in GitHub Desktop.
users.class.php
<?php
# Класс пользователей
class Users extends UsersBase
{
public function authPage($sTemplate, $sTitle = '', array $aData = array())
{
tpl::includeJS('users.auth', false, 4);
$aData['back'] = Request::referer(static::urlBase());
return $this->showShortPage($sTitle, $this->viewPHP($aData, $sTemplate));
}
/**
* Авторизация
*/
public function login()
{
switch ($this->input->getpost('step', TYPE_STR))
{
case 'resend-activation': # Повторная отправка письма "активации"
{
$aResponse = array();
do {
$aData = $this->input->postgetm(array(
'email' => array(TYPE_NOTAGS, 'len' => 100), # E-mail
'pass' => TYPE_NOTRIM, # Пароль (в открытом виде)
));
extract($aData);
if (!$this->security->validateReferer()) {
$this->errors->reloadPage(); break;
}
# не чаще чем раз в {X} секунд с одного IP (для одного пользователя)
if (Site::i()->preventSpam('users-login-resend-activation', 5, false)) {
$this->errors->set(_t('', 'Повторите попытку через несколько секунд'));
break;
}
# уже авторизован
if (User::id()) {
$this->errors->reloadPage();
break;
}
# проверяем email
if (!$this->input->isEmail($email)) {
$this->errors->set(_t('users', 'E-mail адрес указан некорректно'), 'email');
break;
}
$userData = $this->model->userDataByFilter(array('email'=>$email),
array('user_id', 'email', 'name', 'password', 'password_salt', 'activated', 'activate_key', 'phone_number'));
if (empty($userData) || $userData['activated']) {
$this->errors->reloadPage();
break;
}
# телефон
if (static::registerPhone() && !empty($userData['phone_number'])) {
$this->errors->reloadPage();
break;
}
# проверяем пароль
if ($userData['password'] != $this->security->getUserPasswordMD5($pass, $userData['password_salt'])) {
$this->errors->set(_t('users', 'E-mail или пароль указаны некорректно'), 'email');
break;
}
# генерируем ссылку активации
$activationData = $this->updateActivationKey($userData['user_id'], $userData['activate_key']);
if ( ! $activationData) {
$this->errors->reloadPage();
break;
}
# отправляем письмо для активации аккаунта
$mailData = array(
'id' => $userData['user_id'],
'name' => $userData['name'],
'password' => $pass,
'email' => $email,
'activate_link' => $activationData['link']
);
bff::sendMailTemplate($mailData, 'users_register', $email);
# сохраняем данные для повторной отправки письма
$this->security->sessionStart();
$this->security->setSESSION('users-register-data', $mailData);
$aResponse['redirect'] = static::url('register', array('step'=>'emailed', 'resend'=>1));
} while(false);
$this->ajaxResponseForm($aResponse);
}
break;
}
if (Request::isPOST())
{
$aData = $this->input->postm(array(
'email' => array(TYPE_NOTAGS, 'len' => 100), # E-mail
'pass' => TYPE_NOTRIM, # Пароль
'social' => TYPE_BOOL, # Авторизация через соц. сеть
'remember' => TYPE_BOOL, # Запомнить меня
'back' => TYPE_NOTAGS, # Ссылка возврата
));
extract($aData);
$aResponse = array('success' => false, 'status' => 0);
do {
# уже авторизован
if (User::id()) {
$aResponse['success'] = true;
break;
}
# проверяем корректность email
if (!$this->input->isEmail($email)) {
$this->errors->set(_t('users', 'E-mail адрес указан некорректно'), 'email');
break;
}
# при авторизации проверяем блокировку по IP
if ($mBlocked = $this->checkBan(true)) {
$this->errors->set(_t('users', 'Доступ заблокирован по причине: [reason]', array('reason' => $mBlocked)));
break;
}
# не чаще чем раз в {X} секунд с одного IP (для одного пользователя)
if (Site::i()->preventSpam('users-login', rand(3,6), false)) {
$this->errors->set(_t('', 'Повторите попытку через несколько секунд'));
break;
}
$mResult = $this->userAuth($email, 'email', $pass, false, true);
if ($mResult === true) {
$nUserID = User::id();
# привязываем соц. аккаунт
if ($social) {
$this->social()->authFinish($nUserID);
}
# пересохраняем избранные ОБ из куков в базу
BBS::i()->saveFavoritesToDB($nUserID);
$aResponse['status'] = 2; # успешная авторизация
$aResponse['success'] = true;
if ($remember) {
$this->security->setRememberMe($this->security->getUserLogin(), $this->security->getUserPasswordMD5($pass));
}
} elseif ($mResult === 1) {
$aResponse['status'] = 1; # необходимо активировать аккаунт
$userData = config::get('__users_preactivate_data');
$userData = $this->model->userData($userData['id'], array('user_id as id','email','name','activate_key','phone_number'));
if (static::registerPhone() && !empty($userData['phone_number'])) {
if (empty($userData['activate_key'])) {
# Обновляем ключ активации
$activationData = $this->updateActivationKey($userData['id']);
if (!$activationData) {
$this->errors->set(_t('users', 'Ошибка регистрации, обратитесь к администратору'));
break;
} else {
$userData['activate_key'] = $activationData['key'];
}
}
# Отправляем SMS с кодом активации для подтверждения номера телефона
$this->sms(false)->sendActivationCode($userData['phone_number'], $userData['activate_key']);
$this->security->sessionStart();
$this->security->setSESSION('users-register-data', array(
'id' => $userData['id'],
'name' => $userData['name'],
'password' => $pass,
'phone' => $userData['phone_number'],
'email' => $email,
));
$this->errors->set(_t('users', 'Данный аккаунт неактивирован. <a [link_activate]>Активировать</a>',
array('link_activate'=>'href="'.static::url('register', array('step' => 'phone')).'"')));
} else {
$this->errors->set(_t('users', 'Данный аккаунт неактивирован, перейдите по ссылке отправленной вам в письме.<br /><a [link_resend]>Получить письмо повторно</a>',
array('link_resend'=>'href="#" class="ajax j-resend-activation"')));
}
break;
}
} while (false);
if ($aResponse['success']) {
if (empty($back)
|| strpos($back, '/user/register') !== false
|| strpos($back, '/user/login') !== false
) {
$back = bff::urlBase();
}
$aResponse['redirect'] = $back;
}
$this->ajaxResponseForm($aResponse);
} else {
if (User::id()) {
$this->redirectToCabinet();
}
}
# SEO
$this->urlCorrection(static::url('login'));
$this->setMeta('login');
return $this->authPage('auth.login', _t('users', 'Войдите на сайт с помощью электронной почты или через социальную сеть'), array(
'providers' => $this->social()->getProvidersEnabled()
)
);
}
/**
* Авторизация через соц. сети
*/
public function loginSocial()
{
$this->social()->auth($this->input->get('provider', TYPE_NOTAGS));
}
/**
* Авторизация на фронтенде из админки
*/
public function login_admin()
{
$userID = $this->input->get('uid', TYPE_UINT);
do {
if (!$this->security->validateReferer() || !$userID) break;
$userData = $this->model->userData($userID, array('last_login','email','password'));
if (empty($userData)) break;
$hash = $this->input->get('hash', TYPE_STR);
if (empty($hash)) break;
if ($hash != $this->adminAuthURL($userID, $userData['last_login'], $userData['email'], true)) break;
if ($this->userAuth($userID, 'user_id', $userData['password']) !== true) break;
$this->redirect(bff::urlBase());
} while (false);
$this->errors->error404();
}
/**
* Регистрация
*/
public function register()
{
$this->setMeta('register');
switch ($this->input->getpost('step', TYPE_STR))
{
case 'phone': # Подтверждение номера телефона
{
if (User::id()) {
$this->redirectToCabinet();
}
$registerData = $this->security->getSESSION('users-register-data');
if (empty($registerData['id']) || empty($registerData['phone'])) {
$this->errors->error404();
}
$userID = $registerData['id'];
$userPhone = $registerData['phone'];
$userData = $this->model->userData($userID, array('password','activated','activate_key','blocked','blocked_reason'));
if (empty($userData) || $userData['blocked']) {
$this->errors->error404();
}
if ($userData['activated']) {
$this->userAuth($userID, 'user_id', $userData['password']);
$this->redirectToCabinet();
}
if (Request::isPOST())
{
$act = $this->input->postget('act');
$response = array();
if (!$this->security->validateReferer() || !static::registerPhone()) {
$this->errors->reloadPage(); $act = '';
}
switch ($act)
{
# Проверка кода подтверждения
case 'code-validate':
{
$code = $this->input->postget('code', TYPE_NOTAGS);
if (mb_strtolower($code) !== $userData['activate_key']) {
$this->errors->set(_t('users', 'Код подтверждения указан некорректно'), 'phone');
break;
}
# Активируем аккаунт
$res = $this->model->userSave($userID, array('phone_number_verified'=>1, 'activated' => 1, 'activate_key' => ''));
if ($res) {
bff::i()->callModules('onUserActivated', array($userID));
# Авторизуем
$this->userAuth($userID, 'user_id', $userData['password']);
# Отправляем письмо об успешной регистрации
bff::sendMailTemplate($registerData, 'users_register_phone', $registerData['email']);
$this->security->setSESSION('users-register-data', null);
$response['redirect'] = static::url('register', array('step' => 'finished'));
} else {
bff::log('users: Ошибка активации аккаунта пользователя по коду подтверждения [user-id="'.$userID.'"]');
$this->errors->set(_t('users', 'Ошибка регистрации, обратитесь к администратору'));
break;
}
} break;
# Повторная отправка кода подтверждения
case 'code-resend':
{
$activationData = $this->getActivationInfo();
$res = $this->sms()->sendActivationCode($userPhone, $activationData['key']);
if ($res) {
$activationData = $this->updateActivationKey($userID, $activationData['key']);
if (!$activationData) {
$this->errors->reloadPage();
break;
}
}
} break;
# Смена номера телефона
case 'phone-change':
{
$phone = $this->input->postget('phone', TYPE_NOTAGS, array('len'=>30));
if (!$this->input->isPhoneNumber($phone)) {
$this->errors->set(_t('users', 'Номер телефона указан некорректно'), 'phone');
break;
}
if ($phone === $userPhone) {
break;
}
if ($this->model->userPhoneExists($phone, $userID)) {
$this->errors->set(_t('users', 'Пользователь с таким номером телефона уже зарегистрирован. <a [link_forgot]>Забыли пароль?</a>',
array('link_forgot' => 'href="' . static::url('forgot') . '"')
), 'phone'
);
break;
}
$res = $this->model->userSave($userID, array(
'phone_number' => $phone,
'phone_number_verified' => 0,
));
if (!$res) {
bff::log('users: Ошибка обновления номера телефона [user-id="'.$userID.'"]');
$this->errors->reloadPage();
} else {
$registerData['phone'] = $phone;
$response['phone'] = '+'.$phone;
$this->sms()->sendActivationCode($phone, $userData['activate_key']);
$this->security->setSESSION('users-register-data', $registerData);
}
} break;
}
$this->ajaxResponseForm($response);
}
//
return $this->authPage('auth.register.phone', _t('users', 'Подтверждение номера мобильного телефона'), $registerData);
} break;
case 'emailed': # Уведомление о письме "активации"
{
if (User::id()) {
$this->redirectToCabinet();
}
$aData = $this->security->getSESSION('users-register-data');
if (!empty($aData['id'])) {
$aUser = $this->model->userData($aData['id'], array('activated', 'blocked','phone_number'));
if (empty($aUser) || $aUser['activated'] || $aUser['blocked']) {
$aData = false;
}
}
if (static::registerPhone() && !empty($aUser['phone_number'])) {
$this->errors->error404();
}
if (Request::isPOST()) {
if (!$this->security->validateReferer()) {
$this->errors->reloadPage();
} else {
if (!User::id() && !empty($aData)) {
# Повторная отправка письма об успешной регистрации
bff::sendMailTemplate($aData, 'users_register', $aData['email']);
$this->security->setSESSION('users-register-data', null);
}
}
$this->ajaxResponseForm();
}
$bResend = $this->input->get('resend', TYPE_BOOL);
$sTitle = ( $bResend ? _t('users', 'Письмо отправлено') : _t('users', 'Регистрация завершена') );
return $this->authPage('auth.register.emailed', $sTitle, array('retry_allowed' => !empty($aData)));
}
break;
case 'social': # Регистрация через аккаунт в соц. сети
{
if (User::id()) {
if (Request::isPOST()) {
$this->errors->reloadPage();
$this->ajaxResponseForm();
}
$this->redirectToCabinet();
}
$aSocialData = $this->social()->authData();
if (Request::isPOST()) {
$aResponse = array('exists' => false);
$p = $this->input->postm(array(
'email' => array(TYPE_NOTAGS, 'len' => 100), # E-mail
'agreement' => TYPE_BOOL, # Пользовательское соглашение
)
);
extract($p);
do {
if (!$this->security->validateReferer() || empty($aSocialData)) {
$this->errors->reloadPage();
break;
}
if (!$this->input->isEmail($email)) {
$this->errors->set(_t('users', 'E-mail адрес указан некорректно'), 'email');
break;
}
if ($mBanned = $this->checkBan(true, $email)) {
$this->errors->set(_t('users', 'Доступ заблокирован по причине: [reason]', array('reason' => $mBanned)));
break;
}
if ($this->model->userEmailExists($email)) {
$aResponse['exists'] = true;
break;
}
if (!$agreement) {
$this->errors->set(_t('users', 'Пожалуйста подтвердите, что Вы согласны с пользовательским соглашением'), 'agreement');
}
if (!$this->errors->no()) {
break;
}
# Создаем аккаунт пользователя + генерируем пароль
$aUserData = $this->userRegister(array(
'name' => $aSocialData['name'], # ФИО из соц. сети
'email' => $email, # E-mail
)
);
if (empty($aUserData)) {
$this->errors->set(_t('users', 'Ошибка регистрации, обратитесь к администратору'));
break;
}
$nUserID = $aUserData['user_id'];
# Загружаем аватар из соц. сети
if (!empty($aSocialData['avatar'])) {
$this->avatar($nUserID)->uploadSocial($aSocialData['provider_id'], $aSocialData['avatar'], true);
}
# Закрепляем соц. аккаунт за пользователем
$this->social()->authFinish($nUserID);
# Активируем аккаунт пользователя без подтверждения email адреса
if (!config::sys('users.register.social.email.activation', TYPE_BOOL))
{
$res = $this->model->userSave($nUserID, array(
'activated' => 1
));
if (!$res) {
$this->errors->reloadPage(); break;
}
$res = $this->userAuth($nUserID, 'user_id', $aUserData['password'], false);
if ($res!==true) {
$this->errors->reloadPage(); break;
}
# Отправляем письмо об успешной регистрации
$aMailData = array(
'name' => $aSocialData['name'],
'password' => $aUserData['password'],
'email' => $email,
);
bff::sendMailTemplate($aMailData, 'users_register_auto', $email);
$aResponse['success'] = true;
$aResponse['redirect'] = static::url('register', array('step' => 'finished'));
break;
}
# Отправляем письмо для активации аккаунта
$aMailData = array(
'id' => $nUserID,
'name' => $aSocialData['name'],
'password' => $aUserData['password'],
'email' => $email,
'activate_link' => $aUserData['activate_link']
);
bff::sendMailTemplate($aMailData, 'users_register', $email);
# Сохраняем данные для повторной отправки письма
$this->security->sessionStart();
$this->security->setSESSION('users-register-data', $aMailData);
$aResponse['success'] = true;
$aResponse['redirect'] = static::url('register', array('step' => 'emailed')); # url результирующей страницы
} while (false);
$this->ajaxResponseForm($aResponse);
}
# Данные о процессе регистрации через соц.сеть некорректны, причины:
# 1) неудалось сохранить в сессии
# 2) повторная попытка, вслед за успешной (случайный переход по ссылке)
if (empty($aSocialData)) {
$this->redirect(static::url('register'));
}
# Аватар по-умолчанию
if (empty($aSocialData['avatar'])) {
$aSocialData['avatar'] = UsersAvatar::url(0, '', UsersAvatar::szNormal);
}
return $this->authPage('auth.register.social', _t('users', 'Для завершения регистрации введите Вашу электронную почту'), $aSocialData);
}
break;
case 'finished': # Страница успешной регистрации
{
return $this->authPage('auth.message', _t('users', 'Вы успешно зарегистрировались!'), array(
'message' => _t('users', 'Теперь вы можете <a [link_home]>перейти на главную страницу</a> или <a [link_profile]>в настройки своего профиля</a>.',
array(
'link_home' => 'href="' . bff::urlBase() . '"',
'link_profile' => 'href="' . static::url('my.settings') . '"'
)
)
)
);
}
break;
}
$bPhone = static::registerPhone(); # задействовать: номер телефона
$bCaptcha = (bool)config::sys('users.register.captcha', TYPE_BOOL); # задействовать: капчу
$bPasswordConfirm = (bool)config::sys('users.register.passconfirm', true, TYPE_BOOL); # задействовать: подтверждение пароля
if (Request::isPOST()) {
$aResponse = array('captcha' => false);
if (User::id()) {
$this->ajaxResponseForm($aResponse);
}
$aData = $this->input->postm(array(
'phone' => array(TYPE_NOTAGS, 'len' => 30), # Номер телефона
'email' => array(TYPE_NOTAGS, 'len' => 100), # E-mail
'pass' => TYPE_NOTRIM, # Пароль
'pass2' => TYPE_NOTRIM, # Подтверждение пароля
'back' => TYPE_NOTAGS, # Ссылка возврата
'captcha' => TYPE_STR, # Капча
'agreement' => TYPE_BOOL, # Пользовательское соглашение
)
);
extract($aData);
$aResponse['back'] = $back;
do {
if (!$this->security->validateReferer()) {
$this->errors->reloadPage();
break;
}
if ($bPhone && ! $this->input->isPhoneNumber($phone)) {
$this->errors->set(_t('users', 'Номер телефона указан некорректно'), 'phone');
break;
}
if (!$this->input->isEmail($email)) {
$this->errors->set(_t('users', 'E-mail адрес указан некорректно'), 'email');
break;
}
if ($mBanned = $this->checkBan(true, $email)) {
$this->errors->set(_t('users', 'Доступ заблокирован по причине: [reason]', array('reason' => $mBanned)));
break;
}
if ($bPhone && $this->model->userPhoneExists($phone)) {
$this->errors->set(_t('users', 'Пользователь с таким номером телефона уже зарегистрирован. <a [link_forgot]>Забыли пароль?</a>',
array('link_forgot' => 'href="' . static::url('forgot') . '"')
), 'phone'
);
break;
}
if ($this->model->userEmailExists($email)) {
$this->errors->set(_t('users', 'Пользователь с таким e-mail адресом уже зарегистрирован. <a [link_forgot]>Забыли пароль?</a>',
array('link_forgot' => 'href="' . static::url('forgot') . '"')
), 'email'
);
break;
}
if (empty($pass)) {
$this->errors->set(_t('users', 'Укажите пароль'), 'pass');
} elseif (mb_strlen($pass) < $this->passwordMinLength) {
$this->errors->set(_t('users', 'Пароль не должен быть короче [min] символов', array('min' => $this->passwordMinLength)), 'pass');
} else {
if ($bPasswordConfirm && $pass != $pass2) {
$this->errors->set(_t('users', 'Подтверждение пароля указано неверно'), 'pass2');
}
}
if ($bCaptcha) {
$oProtection = new CCaptchaProtection();
if (empty($captcha) || !$oProtection->valid($this->input->cookie('c2'), $captcha)) {
$this->errors->set(_t('users', 'Результат с картинки указан некорректно'), 'captcha');
$aResponse['captcha'] = true;
Request::deleteCOOKIE('c2');
}
}
if (!$agreement) {
$this->errors->set(_t('users', 'Пожалуйста подтвердите, что Вы согласны с пользовательским соглашением'), 'agreement');
}
# не чаще чем раз в {X} секунд с одного IP (для одного пользователя)
if ($this->errors->no()) {
Site::i()->preventSpam('users-register', 30);
}
if (!$this->errors->no()) {
break;
}
# Создаем аккаунт пользователя
$aUserData = array(
'email' => $email,
'password' => $pass,
);
if ($bPhone) {
$aUserData['phone_number'] = $phone;
}
$aUserData = $this->userRegister($aUserData);
if (empty($aUserData)) {
$this->errors->set(_t('users', 'Ошибка регистрации, обратитесь к администратору'));
break;
}
$aResponse['success'] = true;
$aResponse['redirect'] = static::url('register', array('step' => ($bPhone?'phone':'emailed'))); # url результирующей страницы
# Отправляем письмо для активации аккаунта
$aMailData = array(
'id' => $aUserData['user_id'],
'name' => '',
'password' => $pass,
'phone' => $phone,
'email' => $email,
'activate_link' => $aUserData['activate_link']
);
if ($bPhone) {
# Отправляем SMS с кодом активации для подтверждения номера телефона
# Письмо отправим после успешного подтверждения
$this->sms(false)->sendActivationCode($phone, $aUserData['activate_key']);
} else {
bff::sendMailTemplate($aMailData, 'users_register', $email);
}
# Сохраняем данные для повторной отправки письма
$this->security->sessionStart();
$this->security->setSESSION('users-register-data', $aMailData);
} while (false);
$this->ajaxResponseForm($aResponse);
} else {
if (User::id()) {
$this->redirectToCabinet();
}
}
# seo
$this->urlCorrection(static::url('register'));
return $this->authPage('auth.register', _t('users', 'Зарегистрируйтесь на сайте с помощью электронной почты или через социальную сеть'), array(
'phone_on' => $bPhone,
'captcha_on' => $bCaptcha,
'pass_confirm_on' => $bPasswordConfirm,
'providers' => $this->social()->getProvidersEnabled()
)
);
}
/**
* Активация пользователя
*/
public function activate()
{
if (User::id()) {
$this->redirectToCabinet();
}
# ключ активации
$sKey = $this->input->get('key', TYPE_STR);
# ключ переписки
$bMessageRedirect = false;
$sMessageKey = $this->input->get('msg', TYPE_NOTAGS);
if (!empty($sMessageKey)) {
list($nAuthorID, $nInterlocutorID) = explode('-', (strpos($sMessageKey, '-') !== false ? $sMessageKey : '0-0-0'), 3);
$nAuthorID = intval($nAuthorID);
$nInterlocutorID = intval($nInterlocutorID);
$bMessageRedirect = ($nAuthorID > 0 && $nInterlocutorID > 0);
}
$bAutoRegistration = ($bMessageRedirect || $this->input->get('ar', TYPE_BOOL));
$aUserData = $this->model->userDataByFilter(array(
'activated' => 0,
'blocked' => 0,
array('activate_expire > :expire', ':expire' => $this->db->now()),
'activate_key' => $sKey,
), array('user_id', 'email', 'password', 'password_salt', 'name', 'activated')
);
# Не нашли пользователя по ключу:
# 1) Срок ключа истек / ключ некорректный
# 2) Пользователь активирован / заблокирован
if (empty($aUserData)) {
# При переходе по ссылке "прочитать сообщение..."
if ($bMessageRedirect) {
return $this->authPage('auth.message', _t('users', 'Просмотр переписки'), array(
'message' => _t('users', 'Для просмотра переписки необходимо <a [link_auth]>авторизоваться</a>.', array(
'link_auth' => ' href="' . static::url('login') . '"'
)
)
)
);
}
return $this->authPage('auth.message', _t('users', 'Активация аккаунта'), array(
'message' => _t('users', 'Срок действия ключа активации истек.')
)
);
}
$nUserID = $aUserData['user_id'];
# Активируем
$aActivateData = array(
'activated' => 1,
'activate_key' => '',
);
if ($bAutoRegistration) {
$sPassword = func::generator(12); # генерируем новый пароль
$aActivateData['password'] = $aUserData['password'] = $this->security->getUserPasswordMD5($sPassword, $aUserData['password_salt']);
}
$bActivated = $this->model->userSave($nUserID, $aActivateData);
if ($bActivated) {
# Триггер активации аккаунта
bff::i()->callModules('onUserActivated', array($nUserID));
# Отправляем письмо об успешной автоматической регистрации
if ($bAutoRegistration) {
bff::sendMailTemplate(array(
'name' => $aUserData['name'],
'email' => $aUserData['email'],
'password' => $sPassword
),
'users_register_auto', $aUserData['email']
);
}
}
# Авторизуем
$bAuthorized = $this->userAuth($nUserID, 'user_id', $aUserData['password']);
if ($bAuthorized === true) {
# Пересохраняем избранные ОБ из куков в базу
BBS::i()->saveFavoritesToDB($nUserID);
# Редирект на переписку
if ($bMessageRedirect) {
$aInterlocutorData = $this->model->userData($nInterlocutorID, array('user_id', 'login'));
if (!empty($aInterlocutorData)) {
$this->redirect(InternalMail::url('my.messages', array('i' => $aInterlocutorData['login'])));
}
}
}
# Редирект на страницу успешного завершения регистрации
$this->redirect(static::url('register', array('step' => 'finished')));
}
/**
* Восстановление пароля пользователя
*/
public function forgot()
{
# Уже авторизован
if (User::id()) {
if (Request::isAJAX()) {
$this->errors->impossible();
$this->ajaxResponseForm();
}
$this->redirectToCabinet();
}
$sKey = $this->input->getpost('key', TYPE_STR, array('len' => 100));
$bSocial = $this->input->getpost('social', TYPE_BOOL);
if (!empty($sKey)) {
# Шаг2: Смена пароля
if (Request::isAJAX()) {
do {
if (!$this->security->validateReferer()) {
$this->errors->reloadPage();
break;
}
# Ищем по "ключу восстановления"
$aData = $this->model->userDataByFilter(array(
'blocked' => 0, # незаблокированные аккаунты
'activate_key' => $sKey,
array('activate_expire > :expire', ':expire' => $this->db->now()),
), array('user_id', 'email', 'password', 'password_salt', 'activated')
);
# Не нашли, возможные причины:
# 1) Истек срок действия ссылки восстановления / неверная ссылка восстановления
# 2) Аккаунт заблокирован
if (empty($aData)) {
$this->errors->set(_t('users', 'Срок действия ссылки восстановления пароля истек или ссылка некорректна, <a href="[link_fogot]">повторите попытку</a>.',
array('link_fogot' => static::url('forgot'))
)
);
break;
}
# Проверяем новый пароль
$password = $this->input->post('pass', TYPE_NOTRIM);
if (mb_strlen($password) < $this->passwordMinLength) {
$this->errors->set(_t('users', 'Пароль не должен быть короче [min] символов', array('min' => $this->passwordMinLength)), 'pass');
break;
}
$nUserID = $aData['user_id'];
# Cохраняем новый пароль + активируем
$this->model->userSave($nUserID, array(
'password' => $this->security->getUserPasswordMD5($password, $aData['password_salt']),
'activated' => 1, # активируем, если аккаунт еще НЕ активирован
'activate_key' => '', # сбрасываем ключ
));
# Закрепляем соц. аккаунт за профилем
if ($bSocial) {
$this->social()->authFinish($nUserID);
}
} while (false);
$this->ajaxResponseForm();
}
return $this->authPage('auth.forgot.finish', _t('users', 'Введите новый пароль'), array(
'key' => $sKey,
'social' => $bSocial,
)
);
} else {
# Шаг1: Инициация восстановления пароля по E-mail адресу
if (Request::isAJAX()) {
$email = $this->input->post('email', TYPE_STR);
do {
if (!$this->security->validateReferer()) {
$this->errors->reloadPage();
break;
}
# Проверяем E-mail
if (!$this->input->isEmail($email)) {
$this->errors->set(_t('users', 'E-mail адрес указан некорректно'), 'email');
break;
}
# Получаем данные пользователя
# - восстановление пароля для неактивированных аккаунтов допустимо
$aData = $this->model->userDataByFilter(array('email' => $email, 'blocked' => 0),
array('user_id', 'name', 'activated', 'activate_expire')
);
if (empty($aData)) {
$this->errors->set(_t('users', 'Указанный e-mail в базе не найден'), 'email');
break;
}
/**
* Генерируем "ключ восстановления", помечаем период его действия.
* В случае если аккаунт неактивирован, период действия ключа восстановления пароля будет равен
* периоду действия ссылки активации аккаунта, поскольку задействуется
* одно и тоже поле "activate_expire"
*/
$sKey = func::generator(20);
$bSaved = $this->model->userSave($aData['user_id'], array(
'activate_key' => $sKey,
'activate_expire' => (!$aData['activated'] ? $aData['activate_expire'] :
date('Y-m-d H:i:s', strtotime('+4 hours'))),
)
);
if (!$bSaved) {
$this->errors->reloadPage();
} else {
# Отправляем письмо с инcтрукцией о смене пароля
bff::sendMailTemplate(array(
'link' => static::url('forgot', array('key' => $sKey, 'social' => $bSocial)),
'email' => $email,
'name' => $aData['name']
), 'users_forgot_start', $email
);
}
} while (false);
$this->ajaxResponseForm();
}
# seo
$this->urlCorrection(static::url('forgot'));
$this->setMeta('forgot');
return $this->authPage('auth.forgot.start', _t('users', 'Введите электронную почту, которую вы указывали при регистрации'), array(
'social' => $bSocial,
)
);
}
}
/**
* Выход
*/
public function logout()
{
$sRedirect = bff::urlBase();
if (User::id()) {
$sReferer = Request::referer();
# оставляем пользователя на текущей странице,
# за исключением следующих:
$aWrongReferers = array(
'/user/login',
'/user/register',
'/cabinet/',
'/item/edit',
'/item/success',
'/item/activate',
);
if (!empty($sReferer)) {
foreach ($aWrongReferers as $v) {
if (strpos($sReferer, $v) !== false) {
$sReferer = false;
break;
}
}
if (!empty($sReferer)) {
$sRedirect = $sReferer;
}
}
if ($this->security->validateReferer()) {
$this->security->sessionDestroy(-1, true);
}
}
$this->redirect($sRedirect);
}
/**
* Профиль пользователя
*/
public function profile()
{
$login = $this->input->get('login', TYPE_STR);
# Данные пользователя
$user = $this->model->userDataByFilter(array('login' => $login), array(
'user_id',
'user_id_ex',
'shop_id',
'name',
'login',
'sex',
'activated',
'blocked',
'blocked_reason',
'avatar',
'created',
'region_id',
'reg1_country',
'phone_number',
'phone_number_verified',
'phones',
'skype',
'icq'
)
);
if (empty($user)) {
$this->errors->error404();
}
if ($user['blocked']) {
return $this->showInlineMessage(_t('users', 'Аккаунт пользователя был заблокирован по причине:<br /><b>[reason]</b>',
array('reason' => $user['blocked_reason'])
)
);
}
# Подготовка данных
$userID = $user['user_id'];
if (empty($user['name'])) {
$user['name'] = $user['login'];
}
$user['avatar'] = UsersAvatar::url($userID, $user['avatar'], UsersAvatar::szNormal, $user['sex']);
if (!empty($user['region_id'])) {
$user['region_title'] = Geo::regionTitle($user['region_id']);
# разворачиваем данные о регионе: region_id => reg1_country, reg2_region, reg3_city
$aRegions = Geo::model()->regionParents($user['region_id']);
$user = array_merge($user, $aRegions['db']);
$user['country_title'] = Geo::regionTitle($user['reg1_country']);
}
$user['phones'] = (!empty($user['phones']) ? func::unserialize($user['phones']) : array());
if (static::registerPhoneContacts() && $user['phone_number'] && $user['phone_number_verified']) {
array_unshift($user['phones'], array('v'=>$user['phone_number'],'m'=>mb_substr($user['phone_number'], 0, 2) . 'x xxx xxxx'));
}
$user['skype'] = (!empty($user['skype']) ? mb_substr($user['skype'], 0, 2) . 'xxxxx' : '');
$user['icq'] = (!empty($user['icq']) ? mb_substr($user['icq'], 0, 2) . 'xxxxx' : '');
$user['has_contacts'] = ($user['phones'] || $user['skype'] || $user['icq']);
# Разделы профиля
$tab = trim($this->input->getpost('tab', TYPE_NOTAGS), ' /');
$tabs = array(
'items' => array(
't' => _t('users', 'Объявления пользователя'),
'm' => 'BBS',
'ev' => 'user_items',
'url' => static::urlProfile($user['login']),
'a' => false
),
);
if (!isset($tabs[$tab])) {
$tab = 'items';
}
$tabs[$tab]['a'] = true;
$user['profile_link'] = static::urlProfile($login);
$user['profile_link_dynamic'] = static::urlProfile($login, '', array(), true);
$data = array(
'content' => call_user_func(array(bff::module($tabs[$tab]['m']), $tabs[$tab]['ev']), $userID, $user),
'tabs' => &$tabs,
'user' => &$user,
'is_owner' => User::isCurrent($userID),
);
return $this->viewPHP($data, 'profile');
}
/**
* Кабинет пользователя (layout)
*/
public function my()
{
$aData = array('shop_open' => false);
$tab = $this->input->get('tab', TYPE_NOTAGS);
$header = $this->my_header_menu();
$counters = User::counter(array());
$balance = User::balance();
$shopID = User::shopID();
$publisher = BBS::publisher();
$tabs = array();
# Магазин
if (isset($header['menu']['shop'])) {
$tabs['shop'] = array(
't' => _t('users', 'Магазин'),
'm' => 'Shops',
'ev' => 'my_shop',
'url' => Shops::url('my.shop'),
);
if ($tab == 'shop/open') {
$this->redirect($tabs['shop']['url']);
}
}
# Объявления
if (isset($header['menu']['items'])) {
$tabs['items'] = array(
't' => ($publisher == BBS::PUBLISHER_USER || !$shopID ?
_t('users', 'Объявления') :
_t('users', 'Частные объявления')
),
'm' => 'BBS',
'url' => BBS::url('my.items')
);
if ($tab == 'shop' && !isset($tabs['shop'])) {
$this->redirect($tabs['items']['url']);
}
} else {
if ($tab == 'items') {
$this->redirect($tabs['shop']['url']);
}
}
# Импорт
if(BBS::importAllowed()){
$tabs['import'] = array(
't' => _t('users', 'Импорт'),
'm' => 'BBS',
'ev' => 'my_import',
'url' => BBS::url('my.import'),
);
}
# Избранные объявления
$tabs['favs'] = array(
't' => _t('users', 'Избранные'),
'm' => 'BBS',
'url' => BBS::url('my.favs'),
);
# Сообщения
$tabs['messages'] = array(
't' => _t('users', 'Сообщения'),
'm' => 'InternalMail',
'url' => InternalMail::url('my.messages'),
'counter' => (!empty($counters['cnt_internalmail_new']) ?
'<span class="u-cabinet__main-navigation__new-message"> +' . $counters['cnt_internalmail_new'] . '</span>' :
''),
);
$tabs['messages/chat'] = array('t' => false, 'm' => 'InternalMail', 'ev' => 'my_chat');
# Счет
if (bff::servicesEnabled()) {
$tabs['bill'] = array(
't' => _t('users', 'Счёт'),
'm' => 'Bills',
'url' => Bills::url('my.history'),
'counter' => (!empty($balance) ?
'<span class="u-cabinet__main-navigation__money"> (' . $balance . ' ' . Site::currencyDefault() . ')</span>' :
''),
);
}
# Настройки
$tabs['settings'] = array(
't' => _t('users', 'Настройки'),
'm' => 'Users',
'url' => Users::url('my.settings'),
);
# Открыть магазин
if (!$shopID && bff::shopsEnabled()) {
$aData['shop_open'] = array('url' => Shops::url('my.open'), 'active' => ($tab == 'shop/open'));
$tabs['shop/open'] = array(
't' => false,
'm' => 'Shops',
'ev' => 'my_open',
'url' => $aData['shop_open']['url']
);
}
if (!isset($tabs[$tab])) {
if (Request::isAJAX()) {
$this->errors->impossible();
$this->ajaxResponseForm();
} else {
$this->errors->error404();
}
}
if (!User::id()) {
if (Request::isAJAX() && $tab != 'favs') {
$this->errors->reloadPage();
$this->ajaxResponseForm();
}
}
$aData['content'] = call_user_func(array(
bff::module($tabs[$tab]['m']),
(isset($tabs[$tab]['ev']) ? $tabs[$tab]['ev'] : 'my_' . $tab)
)
);
if ($tab == 'messages/chat') {
$tab = 'messages';
}
$tabs[$tab]['active'] = true;
$aData += array(
'tabs' => &$tabs,
'tab' => $tab,
'user' => User::data(array('name', 'shop_id')),
);
$this->seo()->robotsIndex(false);
bff::setMeta(_t('users', 'Кабинет пользователя'));
return $this->viewPHP($aData, 'my.layout');
}
/**
* Кабинет: Настройки профиля
*/
public function my_settings()
{
$nUserID = User::id();
$nShopID = User::shopID();
$nPublisher = BBS::publisher();
if (!$nUserID) {
return $this->showInlineMessage(_t('users', 'Для доступа в кабинет необходимо авторизоваться'), array('auth' => true));
}
$this->security->setTokenPrefix('my-settings');
# доступность настроек:
# true - доступна, false - скрыта
$on_contacts = (bool)config::sys('users.settings.contacts', true, TYPE_BOOL); # контактные данные
$on_email = (bool)config::sys('users.settings.email.change', true, TYPE_BOOL); # смена email-адреса
$on_phone = static::registerPhone(); # смена номера телефона
$on_destroy = (bool)config::sys('users.settings.destroy', TYPE_BOOL); # удаление аккаунта
# скрываем настройки контактов пользователя при включенном обязательном магазине (не в статусе заявки)
if ($nShopID && ($nPublisher == BBS::PUBLISHER_SHOP || $nPublisher == BBS::PUBLISHER_USER_TO_SHOP)) {
if (Shops::premoderation()) {
$aShopData = Shops::model()->shopData($nShopID, array('status'));
if (!empty($aShopData['status']) && $aShopData['status'] != Shops::STATUS_REQUEST) {
$on_contacts = false;
}
} else {
$on_contacts = false;
}
}
if (Request::isPOST()) {
$sAction = $this->input->getpost('act', TYPE_STR);
if (!$this->security->validateToken() && $sAction != 'avatar-upload') {
$this->errors->reloadPage();
$this->ajaxResponseForm();
}
$aResponse = array();
switch ($sAction) {
case 'shop': # магазин
{
if (!User::shopID() || !bff::shopsEnabled()) {
$this->errors->reloadPage();
break;
}
Shops::i()->my_settings();
}
break;
case 'contacts': # контактные данные
{
if (!$on_contacts) {
$this->errors->reloadPage();
break;
}
$aData = $this->input->postm(array(
'name' => array(TYPE_NOTAGS, 'len' => 50), # ФИО
'region_id' => TYPE_UINT, # город или 0
'addr_addr' => array(TYPE_NOTAGS, 'len' => 400), # адрес
'addr_lat' => TYPE_NUM, # адрес, координата LAT
'addr_lon' => TYPE_NUM, # адрес, координата LON
'phones' => TYPE_ARRAY_NOTAGS, # телефоны
'skype' => array(TYPE_NOTAGS, 'len' => 32), # skype
'icq' => array(TYPE_NOTAGS, 'len' => 50), # icq
)
);
$this->cleanUserData($aData);
$this->model->userSave($nUserID, $aData);
$this->security->updateUserInfo($aData);
$aResponse['name'] = $aData['name'];
}
break;
case 'avatar-upload': # аватар: загрузка
{
if (!$this->security->validateToken()) {
$this->errors->reloadPage();
$mResult = false;
} else {
$mResult = $this->avatar($nUserID)->uploadQQ(true, true);
}
$aResponse = array(
'success' => ($mResult !== false && $this->errors->no()),
'errors' => $this->errors->get(),
);
if ($mResult !== false) {
$this->security->updateUserInfo(array('avatar' => $mResult['filename']));
$nSex = User::data('sex');
$aResponse = array_merge($aResponse, $mResult);
foreach (array(UsersAvatar::szNormal, UsersAvatar::szSmall) as $size) {
$aResponse[$size] = UsersAvatar::url($nUserID, $mResult['filename'], $size, $nSex);
}
}
$this->ajaxResponse($aResponse, true, false);
}
break;
case 'avatar-delete': # аватар: удаление
{
$bDeleted = $this->avatar($nUserID)->delete(true);
if ($bDeleted) {
$nSex = User::data('sex');
$aResponse[UsersAvatar::szNormal] = UsersAvatar::url(0, false, UsersAvatar::szNormal, $nSex);
$aResponse[UsersAvatar::szSmall] = UsersAvatar::url(0, false, UsersAvatar::szSmall, $nSex);
$this->security->updateUserInfo(array('avatar' => ''));
}
}
break;
case 'social-unlink': # соц. сети: отвязывание
{
$oSocial = $this->social();
$providerKey = $this->input->post('provider', TYPE_STR);
$providerID = $oSocial->getProviderID($providerKey);
if ($providerID) {
$res = $oSocial->unlinkSocialAccountFromUser($providerID, $nUserID);
if (!$res) {
$this->errors->reloadPage();
}
}
}
break;
case 'enotify': # email уведомления
{
$aUserEnotify = $this->input->post('enotify', TYPE_ARRAY_UINT);
$res = $this->model->userSave($nUserID, array('enotify' => array_sum($aUserEnotify)));
if (empty($res)) {
$this->errors->reloadPage();
}
}
break;
case 'pass': # смена пароля
{
$this->input->postm(array(
'pass0' => TYPE_NOTRIM, # текущий пароль
'pass1' => TYPE_NOTRIM, # новый пароль
), $p
);
extract($p, EXTR_REFS);
if (!User::isCurrentPassword($pass0)) {
$this->errors->set(_t('users', 'Текущий пароль указан некорректно'), 'pass0');
break;
}
if (empty($pass1)) {
$this->errors->set(_t('users', 'Укажите новый пароль'), 'pass1');
} elseif (mb_strlen($pass1) < $this->passwordMinLength) {
$this->errors->set(_t('users', 'Новый пароль не должен быть короче [symbols] символов',
array('symbols' => $this->passwordMinLength)
), 'pass1'
);
} elseif ($pass0 == $pass1) {
$this->errors->set(_t('users', 'Новый пароль не должен совпадать с текущим'), 'pass1');
}
if (!$this->errors->no()) {
break;
}
$sNewPasswordHash = $this->security->getUserPasswordMD5($pass1, User::data('password_salt'));
$res = $this->model->userSave($nUserID, array('password' => $sNewPasswordHash));
if (!empty($res)) {
$this->security->updateUserInfo(array('password' => $sNewPasswordHash));
} else {
$this->errors->reloadPage();
}
}
break;
case 'phone': # смена номера телефона
{
if (!$on_phone) {
$this->errors->reloadPage();
break;
}
$this->input->postm(array(
'phone' => array(TYPE_NOTAGS, 'len' => 30), # новый номер телефона
'code' => TYPE_NOTAGS, # код активации из sms
'step' => TYPE_NOTAGS, # этап
), $p); extract($p, EXTR_REFS);
if (!$this->input->isPhoneNumber($phone)) {
$this->errors->set(_t('users', 'Номер телефона указан некорректно'), 'phone');
break;
}
if ($this->model->userPhoneExists($phone, $nUserID)) {
$this->errors->set(_t('users', 'Пользователь с таким номером телефона уже зарегистрирован'), 'phone');
break;
}
if ($step == 'code-send') {
$activationData = $this->getActivationInfo();
$res = $this->sms()->sendActivationCode($phone, $activationData['key']);
if ($res) {
$activationData = $this->updateActivationKey($nUserID, $activationData['key']);
if ( ! $activationData) {
$this->errors->reloadPage();
break;
}
}
} else if ($step == 'finish') {
$aUserData = $this->model->userData($nUserID, array('activate_key'));
if (empty($aUserData['activate_key'])) {
$this->errors->reloadPage(); break;
}
if (mb_strtolower($aUserData['activate_key']) !== mb_strtolower($code)) {
$this->errors->set(_t('users', 'Код подтверждения указан некорректно'), 'code');
break;
}
$res = $this->model->userSave($nUserID, array(
'phone_number' => $phone,
'phone_number_verified' => 1,
'activate_key' => '',
));
if (!empty($res)) {
$aResponse['phone'] = '+'.$phone;
} else {
$this->errors->reloadPage();
}
}
}
break;
case 'email': # смена email
{
if (!$on_email) {
$this->errors->reloadPage();
break;
}
$this->input->postm(array(
'email' => array(TYPE_NOTAGS, 'len' => 100), # новый email
'pass' => TYPE_NOTRIM, # текущий пароль
), $p
);
extract($p, EXTR_REFS);
if (!User::isCurrentPassword($pass)) {
$this->errors->set(_t('users', 'Текущий пароль указан некорректно'), 'pass');
break;
}
if (!$this->input->isEmail($email)) {
$this->errors->set(_t('users', 'E-mail адрес указан некорректно'), 'email');
break;
}
if ($this->model->userEmailExists($email)) {
$this->errors->set(_t('users', 'Пользователь с таким e-mail адресом уже зарегистрирован'), 'email');
break;
}
$res = $this->model->userSave($nUserID, array('email' => $email));
if (!empty($res)) {
$aResponse['email'] = $email;
$this->security->updateUserInfo(array('email' => $email));
} else {
$this->errors->reloadPage();
}
}
break;
case 'destroy': # удаление аккаунта
{
if (!$on_destroy) {
$this->errors->reloadPage();
break;
}
$pass = $this->input->post('pass', TYPE_NOTRIM);
if (!User::isCurrentPassword($pass)) {
$this->errors->set(_t('users', 'Текущий пароль указан некорректно'), 'pass');
break;
}
# TODO
$aResponse['redirect'] = bff::urlBase();
}
break;
default:
{
$this->errors->impossible();
}
break;
}
$this->ajaxResponseForm($aResponse);
}
$aData = $this->model->userData($nUserID, array(
'user_id as id',
'email',
'phone_number',
'phone_number_verified',
'name',
'enotify',
'phones',
'skype',
'icq',
'avatar',
'sex',
'addr_addr',
'addr_lat',
'addr_lon',
'region_id'
), true
);
if (empty($aData)) {
# ошибка получения данных о пользователе
bff::log('Неудалось получить данные о пользователе #' . $nUserID . ' [users::my_settings]');
$this->security->sessionDestroy();
}
$aData['avatar_normal'] = UsersAvatar::url($nUserID, $aData['avatar'], UsersAvatar::szNormal, $aData['sex']);
$aData['avatar_maxsize'] = $this->avatar($nUserID)->getMaxSize();
# координаты по-умолчанию
Geo::mapDefaultCoordsCorrect($aData['addr_lat'], $aData['addr_lon']);
# данные о привязанных соц. аккаунтах
$oSocial = $this->social();
$aSocialProviders = $oSocial->getProvidersEnabled();
$aSocialUser = $oSocial->getUserSocialAccountsData($nUserID);
foreach ($aSocialUser as $k => $v) {
if (isset($aSocialProviders[$k]) && strpos($v['profile_data'], 'a:') === 0) {
$aSocialProviders[$k]['user'] = func::unserialize($v['profile_data']);
}
}
$aData['social'] = $aSocialProviders;
# настройки уведомлений
$aData['enotify'] = $this->getEnotifyTypes($aData['enotify']);
# активный подраздел настроек
$tab = $this->input->getpost('t', TYPE_NOTAGS);
if (empty($tab)) {
if (!$on_contacts) {
$tab = 'shop';
} else {
if (!$nShopID || $nPublisher == BBS::PUBLISHER_USER) {
$tab = 'contacts';
}
}
}
$aData['tab'] = & $tab;
$aData['on'] = array(
'contacts' => $on_contacts,
'phone' => $on_phone,
'email' => $on_email,
'destroy' => $on_destroy,
);
return $this->viewPHP($aData, 'my.settings');
}
/**
* Меню пользователя (шапка, кабинет)
*/
public function my_header_menu()
{
static $data;
if (isset($data)) {
return $data;
}
$data = array();
# данные о пользователе + счетчики
if (User::id()) {
$data['user'] = User::data(array('name', 'shop_id')) + User::counter(array());
} else {
$data['user'] = array('name' => _t('users', 'Гость'), 'shop_id' => 0);
}
# меню пользователя:
$data['menu'] = array();
$menu = & $data['menu'];
# > магазин
$shopID = User::shopID();
$shopsEnabled = bff::shopsEnabled();
$publisher = BBS::publisher();
if ($shopsEnabled && $shopID) {
$menu['shop'] = array(
'i' => 'fa fa-shopping-cart',
't' => _t('header', 'магазин'),
'url' => Shops::url('my.shop')
);
}
# > объявления
$menu['items'] = array(
't' => (
($publisher == BBS::PUBLISHER_USER || !$data['user']['shop_id']) ?
_t('users', 'объявления') :
_t('users', 'частные объявления')
),
'i' => 'fa fa-list',
'url' => BBS::url('my.items')
);
# скрываем раздел кабинета "объявления"
if ($shopsEnabled && $shopID) {
# при публикации только от "магазинов"
if ($publisher == BBS::PUBLISHER_SHOP) {
unset($menu['items']);
} else {
if ($publisher == BBS::PUBLISHER_USER_TO_SHOP) {
# после одобрения заявки магазина
if (Shops::model()->shopStatus($shopID) !== Shops::STATUS_REQUEST) {
unset($menu['items']);
}
}
}
}
# > избранные
$menu['favs'] = array('i' => 'fa fa-star', 't' => _t('users', 'избранные'), 'url' => BBS::url('my.favs'));
# > сообщения
$menu['messages'] = array(
'i' => 'fa fa-comment',
't' => _t('users', 'сообщения'),
'url' => InternalMail::url('my.messages')
);
$menu[] = 'D'; // разделитель
# > счет
if (bff::servicesEnabled()) {
$menu['bill'] = array('i' => 'fa fa-retweet', 't' => _t('users', 'счет'), 'url' => Bills::url('my.history'));
}
# > настройки
$menu['settings'] = array(
'i' => 'fa fa-pencil',
't' => _t('users', 'настройки'),
'url' => Users::url('my.settings')
);
$menu[] = 'D'; // разделитель
# > выход
$menu['logout'] = array('i' => 'fa fa-power-off', 't' => _t('users', 'выход'), 'url' => Users::url('logout'));
return $data;
}
# non-actions
protected function redirectToCabinet()
{
$this->redirect(static::url('my.settings'));
}
/**
* Форма отправки сообщения
* @param string $formID ID формы
* @return string HTML
*/
public function writeForm($formID)
{
$aData = array('form_id' => $formID);
return $this->viewPHP($aData, 'write.form');
}
/**
* Обработчик формы отправки сообщения пользователю / магазину
* @param integer $authorID ID отправителя
* @param integer $receiverID ID получателя или 0 (владелец объявления)
* @param integer $itemID ID объявления или 0
* @param boolean $itemRequired ID объявления обязательно ($itemID != 0)
* @param integer|boolean $shopID ID магазина / 0 / -1 (ID магазина объявления)
*/
public function writeFormSubmit($authorID, $receiverID, $itemID, $itemRequired, $shopID)
{
$aResponse = array();
do {
if (!$this->security->validateToken(true, false)) {
$this->errors->reloadPage();
break;
}
if (!$itemID && $itemRequired) {
$this->errors->reloadPage();
break;
}
if ($itemID) {
$itemData = BBS::model()->itemData($itemID, array(
'id',
'user_id',
'shop_id',
'link',
'title',
'status',
'deleted'
)
);
if (empty($itemData) || $itemData['deleted'] || $itemData['status'] != BBS::STATUS_PUBLICATED) {
$this->errors->reloadPage();
break;
}
}
if (!$authorID) {
$email = $this->input->postget('email', TYPE_NOTAGS, array('len' => 150));
if (!$this->input->isEmail($email)) {
$this->errors->set(_t('', 'E-mail адрес указан некорректно'), 'email');
break;
}
}
$message = $this->input->post('message', TYPE_STR);
$message = $this->input->cleanTextPlain($message, 1000, false);
if (mb_strlen($message) < 10) {
$this->errors->set(_t('view', 'Сообщение слишком короткое'), 'message');
break;
}
if (!$authorID) {
$userData = Users::model()->userDataByFilter(array('email' => $email), array(
'user_id',
'blocked',
'blocked_reason'
)
);
if (empty($userData)) {
# создаем новый аккаунт (неактивированный)
$userData = Users::i()->userRegister(array('email' => $email));
if (!empty($userData['user_id'])) {
$authorID = $userData['user_id'];
} else {
# ошибка регистрации
$this->errors->reloadPage();
break;
}
} else {
if ($userData['blocked']) {
$this->errors->set(_t('users', 'Данный аккаунт заблокирован по причине: [reason]',
array('reason' => $userData['blocked_reason'])
)
);
break;
}
$authorID = $userData['user_id'];
}
}
if ($itemID) {
$receiverID = $itemData['user_id'];
if ($shopID === -1) {
$shopID = $itemData['shop_id'];
}
}
# проверяем получателя
$receiver = $this->model->userData($receiverID, array('activated', 'blocked'));
if (empty($receiver) || $receiver['blocked'] || User::isCurrent($receiverID)) {
$this->errors->reloadPage();
break;
}
if ($authorID && $receiverID && ($authorID !== $receiverID)) {
# не чаще чем раз в {X} секунд с одного IP (для одного пользователя)
if (Site::i()->preventSpam('users-write-form', 5)) {
break;
}
# отправляем сообщение владельцу ОБ
$messageID = InternalMail::model()->sendMessage($authorID, $receiverID, $shopID, $message,
InternalMail::i()->attachUpload(),
$itemID
);
if ($messageID > 0 && $itemID) {
# обновляем счетчик сообщений ОБ
BBS::model()->itemSave($itemID, array(
'messages_total = messages_total + 1',
'messages_new = messages_new + 1',
)
);
}
}
} while (false);
$this->iframeResponseForm($aResponse);
}
public function ajax()
{
$response = array();
switch ($this->input->getpost('act', TYPE_STR)) {
case 'user-contacts': # просмотр контактов пользователя
{
$ex = $this->input->postget('ex', TYPE_STR);
if (empty($ex)) {
$this->errors->reloadPage();
break;
}
list($ex, $userID) = explode('-', $ex);
$user = $this->model->userData($userID, array(
'user_id',
'user_id_ex',
'activated',
'blocked',
'phone_number',
'phone_number_verified',
'phones',
'skype',
'icq'
)
);
if (empty($user) || $user['user_id_ex'] != $ex || !$user['activated'] || $user['blocked'] ||
!$this->security->validateToken(true, false)
) {
$this->errors->reloadPage();
break;
}
if (static::registerPhoneContacts() && $user['phone_number'] && $user['phone_number_verified']) {
if (empty($user['phones'])) $user['phones'] = array();
array_unshift($user['phones'], array('v'=>$user['phone_number']));
}
if (!empty($user['phones'])) {
if (!bff::deviceDetector(bff::DEVICE_PHONE)) {
$phones = array();
foreach ($user['phones'] as $v) $phones[] = $v['v'];
$response['phones'] = '<span><img src="' . Users::contactAsImage($phones) . '" /></span>';
} else {
$phones = '<span>'; $i = 1;
foreach ($user['phones'] as $v) {
$phone = HTML::obfuscate($v['v']);
$phones .= '<a href="tel:'.$phone.'">'.$phone.'</a>';
if ($i++ < sizeof($user['phones'])) {
$phones .= ', ';
}
}
$phones .= '</span>';
$response['phones'] = $phones;
}
}
if (!empty($user['skype'])) {
$skype = HTML::obfuscate($user['skype']);
$response['skype'] = '<a href="skype:' . $skype . '?call">' . $skype . '</a>';
}
if (!empty($user['icq'])) {
$response['icq'] = HTML::obfuscate($user['icq']);
}
}
break;
}
$this->ajaxResponseForm($response);
}
public function cron()
{
if (!bff::cron()) {
return;
}
$this->model->usersCronDeleteNotActivated();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment