Пост посвящается всем пережившим вчерашний конец света ;)
Мой проект (я его упоминал уже как-то, если в двух словах - он про спортивные соревнования) развивается медленно (потому что спросом не пользуется) и спросом не пользуется (потому что развивается медленно). Но раз в год он точно нужен и востребован, и в прошлый раз там даже какое-то количество людей зарегистрировалось. А раз приближается время, когда все эти люди потянутся на мой сайт опять, да не просто потянутся, а обнаружат, что не могут вспомнить свой пароль, то и эту проблему как-то придется решать. А как? Средствами апекса - никак (пока никак, но об этом позже).
Я забыл пароль :(
Ну с кем не бывает. Если забыл, надо или вспоминать, или восстанавливать. А как вспоминать, если вводил его всего один раз, и то год назад? Значит, без нас забывчивому пользователю не обойтись! Идем на страницу 101 (стандарная страница логина), добавляем там элемент с типом Display Only и дефолтным значением<u><a href="f?p=&APP_ID.:102:&APP_SESSION.:">Забыли пароль?</a></u>
В разделе Label удаляем текст ярлыка и выбираем Template "No Label".
К чему такой огород? В принципе, ссылку можно создать, просто добавив в Region Source региона вышеприведенный код. Но тогда ссылка будет нарисована просто в углу, а в нашем случае она будет выставлена аккуратно под полем для ввода пароля и выровнена по левому краю:
Страница восстановления пароля
Страницу восстановления я решил сделать с ajax'ом. Что самое странное, совсем без извращений обойти не удалось. Пожелания мои к странице были следующие:- пользователь для идентификации может ввести логин или адрес электронной почты от своей учетной записи
- в случае, когда логин или почта найдены, сбросить пароль и выслать на указанный в учетной записи адрес письмо с временным паролем
- если не найден логин/пароль - сообщить об этом пользователю
- запрос делать с помощью ajax, выводить на страницу сообщение о результате.
Зато есть возможность это обойти: создаем обычный Display Only элемент страницы, очищаем у него Label, в HTML Form Element Attributes вставляем строчку onclick="recover_pwd()" (это будет наша javascript-функция для восстановления пароля), а Defualt Value - вот такое:
<button type="button">Восстановить</button>
И получаем кнопку, которая выглядит как HTML Button и при этом вызывает javascript.
Код
Javascript-вызов подробно описывать не буду - там почти все то же самое, что и здесь. Только в этот раз будем передавать два параметра вместо одного (еще напомню, что ajax в апекс-приложениях с авторизацией и без работает немного по-разному).Теперь код для смены пароля:
create or replace function "RECOVER_PWD" (p_login VARCHAR2, p_email VARCHAR2) return varchar2 is u_id number; u_mail varchar2(255); by_login boolean; by_email boolean; new_pwd varchar2(255) := '123456'; -- это наш временный пароль new_pwde varchar2(255); begin if p_login is not null then -- находим ID пользователя и email по указанному логину: by_login := true; select id, email into u_id, u_mail from users where login = UPPER(p_login); -- если у пользователя не указан email - сообщаем об этом -- (остальные варианты обработаем позже): if u_mail is null then return('Вы не указали почтового адреса при регистрации. ' || 'Для восстановления учетной записи свяжитесь с администрацией.'); end if; elsif p_email is not null then -- находим ID пользователя и email по указанному почтовому адресу: by_email := true; select id into u_id from users where email = LOWER(p_email); end if; -- если досюда добрались, значит, нашли указанного пользователя и его адрес. -- получаем хэш временного пароля: new_pwde:=dbms_obfuscation_toolkit.md5(input_string => new_pwd); -- хэш - в таблицу: update users set pwd = new_pwde where id = u_id; -- пароль - пользователю на почту: send_recovery_info(nvl(p_email, u_mail), new_pwd); -- и отчитаемся: return('Временный пароль выслан на почтовый адрес, указанный вами при регистрации.'); exception -- в случае, если селекты ничего не нашли, определяем с помощью -- переменных by_login и by_email по какому полю искали: when no_data_found then if by_login then return('Нет ни одной учетной записи с таким именем пользователя'); end if; if by_email then return('Нет ни одной учетной записи с таким адресом электроной почты'); end if; when too_many_rows then -- А это уже караул, кто ж такой бардак в таблице развел??? -- Сделайте уже что-нибудь!!! Только без меня... end;
Соответственно, Application Process для этого вызова выглядит так:
begin htp.prn(recover_pwd(:P102_LOGIN, :P102_EMAIL)); end;
Мы передаем в нашу основную функцию логин и адрес со страницы восстановления пароля, а возвращаемый результат функции - текстовое описание того, что именно произошло - отправляем обратно на страницу, чтобы пользователь знал, что его запрос не исчез в пучине интернета, а как-то обработался. В случае, если все прошло успешно - пользователю на найденный адрес отправляется уведомление (функция send_recovery_info с 43-й строки):
create or replace procedure "SEND_RECOVERY_INFO" (p_email VARCHAR2, p_new_pwd varchar2) is l_body varchar2(32767); res integer; begin l_body := 'Ваш временный пароль: ' || p_new_pwd || '. Поменяйте его как можно быстрее.'; res := APEX_MAIL.SEND(p_email, 'ваш@обратный.адрес', l_body, NULL, 'Восстановление пароля'); end;
Здесь мы используем процедуру SEND из пакета APEX_MAIL - отправить письмо из апекса проще простого, как видите. Помните только, что вторым параметром придется поставить валидный обратный email - рассылать спам вам апекс не даст. Хотя, когда я отправил тестовое письмо самому себе, gmail поместил его в спам и дополнительно сообщил, что письмо, возможно, отправлено не с того адреса, который указан в поле "от кого" - так что хоть спам вы и не рассылаете, но ваши адресаты его получают ;)
А тем временем на странице у пользователя...
...долго сказка сказывается, да быстро код выполняется. Чтобы увидеть ответ, надо его куда-то вывести. Тут либо у апекса некоторые проблемы, либо я что-то не так понял :( Стандартное апексовое окошко вверху страницы (например, такое зелененькое вверху, появляется, когда вы редактируете свойства какой-нибудь страницы) не приспособлено для ajax - его надо заполнять значением перед показом страницы. Можно сделать просто вызов функции alert(), но тогда браузер вам покажет модальное окно с сообщением, а модальные окна без особой необходимости - это ЗлоЪ™ в чистом виде, вам это любой специалист по юзабилити подтвердит. Я решил сделать так: создал элемент с названием P102_RESPONSE и разместил его ниже. Тут опять возник сюрприз... Чтобы поменять значение элемента страницы, я раньше использовал функцию html_GetElement('elementName').value, но тут оказалось, что таким способом можно менять только значения полей для ввода, а для Display Only элементов надо пользоваться функцией $s (вот кстати документация по всем функциям, чтобы долго не искать):function recover_pwd() { /*Ну тут мы посылаем запрос серверу, это все уже умеют делать, получаем ответ... */ var gReturn = get.get(); /* и показываем пользователю: */ $s('P102_RESPONSE', gReturn); }
Вот так можно сделать восстановление пароля. Вроде ничего существенного не забыл...
Комментариев нет:
Отправить комментарий