mirror of
https://github.com/getgrav/grav-plugin-admin.git
synced 2026-05-05 19:16:53 +02:00
forgot password [fixes #28]
This commit is contained in:
@@ -139,6 +139,120 @@ class AdminController
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function taskForgot()
|
||||
{
|
||||
$data = $this->post;
|
||||
|
||||
$username = isset($data['username']) ? $data['username'] : '';
|
||||
$user = !empty($username) ? User::load($username) : null;
|
||||
|
||||
if (!isset($this->grav['Email'])) {
|
||||
$this->admin->setMessage('Cannot reset password. This site is not configured to send emails.');
|
||||
$this->setRedirect('/');
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!$user || !$user->exists()) {
|
||||
$this->admin->setMessage('User with username \'' . $username . '\' does not exist.');
|
||||
$this->setRedirect('/forgot');
|
||||
return true;
|
||||
}
|
||||
|
||||
if (empty($user->email)) {
|
||||
$this->admin->setMessage('Cannot reset password for \'' . $username . '\', no email address is set.');
|
||||
$this->setRedirect('/forgot');
|
||||
return true;
|
||||
}
|
||||
|
||||
$token = md5(uniqid(mt_rand(), true));
|
||||
$expire = time() + 604800; // next week
|
||||
|
||||
$user->reset = $token . '::' . $expire;
|
||||
$user->save();
|
||||
|
||||
$author = $this->grav['config']->get('site.author.name', '');
|
||||
$fullname = $user->fullname ?: $username;
|
||||
$reset_link = rtrim($this->grav['uri']->rootUrl(true), '/') . '/' . trim($this->admin->base, '/') . '/reset/task:reset/user:' . $username . '/token:' . $token;
|
||||
|
||||
$from = $this->grav['config']->get('site.author.email', 'noreply@getgrav.org');
|
||||
$to = $user->email;
|
||||
$subject = $this->grav['config']->get('site.title', 'Website') . ' password reset';
|
||||
$body = $this->grav['twig']->processString('{% include "email/reset.html.twig" %}', [
|
||||
'name' => $fullname,
|
||||
'author' => $author,
|
||||
'reset_link' =>$reset_link
|
||||
]);
|
||||
|
||||
$message = $this->grav['Email']->message($subject, $body, 'text/html')
|
||||
->setFrom($from)
|
||||
->setTo($to);
|
||||
|
||||
$sent = $this->grav['Email']->send($message);
|
||||
|
||||
if ($sent < 1) {
|
||||
$this->admin->setMessage('Failed to email instructions, please try again later.');
|
||||
} else {
|
||||
$this->admin->setMessage('Instructions to reset your password have been sent by email.');
|
||||
}
|
||||
|
||||
$this->setRedirect('/');
|
||||
return true;
|
||||
}
|
||||
|
||||
public function taskReset()
|
||||
{
|
||||
$data = $this->post;
|
||||
|
||||
if (isset($data['password'])) {
|
||||
|
||||
$username = isset($data['username']) ? $data['username'] : null;
|
||||
$user = !empty($username) ? User::load($username) : null;
|
||||
$password = isset($data['password']) ? $data['password'] : null;
|
||||
$token = isset($data['token']) ? $data['token'] : null;
|
||||
|
||||
if (!empty($user) && $user->exists() && !empty($user->reset)) {
|
||||
list($good_token, $expire) = explode('::', $user->reset);
|
||||
|
||||
if ($good_token === $token) {
|
||||
|
||||
if (time() > $expire) {
|
||||
$this->admin->setMessage('Reset link has expired, please try again.');
|
||||
$this->setRedirect('/forgot');
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
unset($user->hashed_password);
|
||||
unset($user->reset);
|
||||
$user->password = $password;
|
||||
$user->save();
|
||||
|
||||
$this->admin->setMessage('Password has been reset.');
|
||||
$this->setRedirect('/');
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
$this->admin->setMessage('Invalid reset link used, please try again.');
|
||||
$this->setRedirect('/forgot');
|
||||
return true;
|
||||
|
||||
} else {
|
||||
$user = $this->grav['uri']->param('user');
|
||||
$token = $this->grav['uri']->param('token');
|
||||
|
||||
if (empty($user) || empty($token)) {
|
||||
$this->admin->setMessage('Invalid reset link used, please try again.');
|
||||
$this->setRedirect('/forgot');
|
||||
return true;
|
||||
}
|
||||
|
||||
$this->admin->forgot = [ 'username' => $user, 'token' => $token ];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function taskClearCache()
|
||||
{
|
||||
$results = Cache::clearCache('standard');
|
||||
|
||||
11
pages/admin/forgot.md
Normal file
11
pages/admin/forgot.md
Normal file
@@ -0,0 +1,11 @@
|
||||
---
|
||||
title: Forgot password
|
||||
|
||||
form:
|
||||
fields:
|
||||
- name: username
|
||||
type: text
|
||||
placeholder: Username
|
||||
autofocus: true
|
||||
---
|
||||
|
||||
17
pages/admin/reset.md
Normal file
17
pages/admin/reset.md
Normal file
@@ -0,0 +1,17 @@
|
||||
---
|
||||
title: Reset password
|
||||
|
||||
form:
|
||||
fields:
|
||||
- name: username
|
||||
type: text
|
||||
placeholder: Username
|
||||
readonly: true
|
||||
- name: password
|
||||
type: password
|
||||
placeholder: Password
|
||||
autofocus: true
|
||||
- name: token
|
||||
type: hidden
|
||||
---
|
||||
|
||||
11
themes/grav/templates/email/base.html.twig
Normal file
11
themes/grav/templates/email/base.html.twig
Normal file
@@ -0,0 +1,11 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
{% block head %}
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
{% endblock %}
|
||||
</head>
|
||||
<body>
|
||||
{% block content %}{% endblock %}
|
||||
</body>
|
||||
</html>
|
||||
12
themes/grav/templates/email/reset.html.twig
Normal file
12
themes/grav/templates/email/reset.html.twig
Normal file
@@ -0,0 +1,12 @@
|
||||
{% extends 'email/base.html.twig' %}
|
||||
|
||||
{% block content %}
|
||||
<p>Dear {{ name }},</p>
|
||||
|
||||
<p>To reset your password, follow <a href="{{ reset_link }}">this link</a> or copy the following URL into your browser's address bar: {{ reset_link }}.</p>
|
||||
|
||||
<p>
|
||||
Kind regards<br />
|
||||
{{ author }}
|
||||
</p>
|
||||
{% endblock %}
|
||||
25
themes/grav/templates/forgot.html.twig
Normal file
25
themes/grav/templates/forgot.html.twig
Normal file
@@ -0,0 +1,25 @@
|
||||
{% extends 'partials/base.html.twig' %}
|
||||
|
||||
{% block page %}
|
||||
<section id="admin-login" class="default-glow-shadow">
|
||||
<h1>
|
||||
Grav forgot password
|
||||
</h1>
|
||||
|
||||
{% include 'partials/messages.html.twig' %}
|
||||
|
||||
<form method="post" action="{{ base_url_relative }}">
|
||||
{% for field in page.header.form.fields %}
|
||||
{% if field.type %}
|
||||
<div>
|
||||
{% include ["forms/fields/#{field.type}/#{field.type}.html.twig", 'forms/fields/text/text.html.twig'] %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
<div class="form-actions secondary-accent">
|
||||
<button type="submit" class="button primary" name="task" value="forgot"><i class="fa fa-paper-plane"></i> Send reset instructions</button>
|
||||
</div>
|
||||
</form>
|
||||
</section>
|
||||
{% endblock %}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
<div class="form-actions secondary-accent">
|
||||
<button type="button" class="button secondary" name="task" value="forgot"><i class="fa fa-exclamation-circle"></i> Forgot</button>
|
||||
<a class="button secondary" href="{{ base_url_relative }}/forgot"><i class="fa fa-exclamation-circle"></i> Forgot</a>
|
||||
<button type="submit" class="button primary" name="task" value="login"><i class="fa fa-sign-in"></i> Login</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
29
themes/grav/templates/reset.html.twig
Normal file
29
themes/grav/templates/reset.html.twig
Normal file
@@ -0,0 +1,29 @@
|
||||
{% extends 'partials/base.html.twig' %}
|
||||
|
||||
{% block page %}
|
||||
<section id="admin-login" class="default-glow-shadow">
|
||||
<h1>
|
||||
Reset Grav password
|
||||
</h1>
|
||||
|
||||
{% include 'partials/messages.html.twig' %}
|
||||
|
||||
<form method="post" action="{{ base_url_relative }}">
|
||||
|
||||
{% for field in page.header.form.fields %}
|
||||
{% set value = attribute(admin.forgot, field.name) is defined ? attribute(admin.forgot, field.name) : null %}
|
||||
|
||||
{% if field.type %}
|
||||
<div>
|
||||
{% include ["forms/fields/#{field.type}/#{field.type}.html.twig", 'forms/fields/text/text.html.twig'] %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
<div class="form-actions secondary-accent">
|
||||
<button type="submit" class="button primary" name="task" value="reset"><i class="fa fa-key"></i> Reset password</button>
|
||||
</div>
|
||||
</form>
|
||||
</section>
|
||||
{% endblock %}
|
||||
|
||||
Reference in New Issue
Block a user